-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Progress Component #121
Changes from all commits
cfb372a
f09f57b
061916b
62a4c5d
67fc0e8
be355c2
b0d5512
3f8d2d2
46463e0
d799baa
429f726
fdd2d48
6c32468
c819403
0fdcf8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import React, {Component, PropTypes} from 'react'; | ||
import classNames from 'classnames'; | ||
import $ from 'jquery'; | ||
import META from 'src/utils/Meta'; | ||
import _ from 'lodash'; | ||
|
||
export default class Progress extends Component { | ||
static propTypes = { | ||
autoSuccess: PropTypes.bool, | ||
children: PropTypes.node, | ||
className: PropTypes.string, | ||
label: PropTypes.oneOf(['ratio', 'percent']), | ||
limitValues: PropTypes.bool, | ||
onActive: PropTypes.func, | ||
onChange: PropTypes.func, | ||
onError: PropTypes.func, | ||
onSuccess: PropTypes.func, | ||
onWarning: PropTypes.func, | ||
percent: PropTypes.number, | ||
precision: PropTypes.number, | ||
random: PropTypes.bool, | ||
showActivity: PropTypes.bool, | ||
total: PropTypes.bool, | ||
value: PropTypes.bool, | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These prop values were taken from semantic ui's progress docs:http://semantic-ui.com/modules/progress.html#/settings There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any of these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically none are, you could possibly make the |
||
|
||
componentDidMount() { | ||
this.element = $(this.refs.element); | ||
this.element.progress({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To cut down on SLOC it'd be nice to spread our progress props of interest here, e.g.
Also, it might be better for UX do a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. -1 to manual DOM manipulation in React, it will freak out if you touch the DOM. In this case, the EDIT There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eanplatter could you give this a try (as an example), it's highly expressive, doesn't require
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will return an array of objects with one key/value pair for each prop: [
{autoSuccess: <this.prop.autoSuccess>},
{label: <this.prop.label>},
...etc
]
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we omit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly what I wanted. Couldn't take it the full mile without the example, but we should be able to then iterate over the elements in the array and pass them into the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assuming the same settings array, we can create the object like this: let settingsObj = {};
settings.forEach(key => settingsObj[key] = this.props[key]);
this.element.progress(settingsObj); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this work?
|
||
autoSuccess: this.props.autoSuccess, | ||
label: this.props.label, | ||
limitValues: this.props.limitValues, | ||
onActive: this.props.onActive, | ||
onChange: this.props.onChange, | ||
onError: this.props.onError, | ||
onSuccess: this.props.onSuccess, | ||
onWarning: this.props.onWarning, | ||
percent: this.props.percent, | ||
precision: this.props.precision, | ||
random: this.props.random, | ||
showActivity: this.props.showActivity, | ||
total: this.props.total, | ||
value: this.props.value, | ||
}); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are also taken from the stardust docs, and represent possible callbacks and plugin properties exposed to the user: http://semantic-ui.com/modules/progress.html#/usage There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the settings accepted as props should be passed to the plugin here. Otherwise, we are defining props that are never used. For instance: <Progress total={1} value={0.2} /> This should do If we instead pass all prop settings to the plugin, then it would mount and animate to 20% complete. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved all props to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Passing React children to a jQuery plugin are we ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...and html classes. |
||
|
||
static _meta = { | ||
library: META.library.stardust, | ||
name: 'Progress', | ||
type: META.type.module, | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Meta info for the component. |
||
|
||
plugin() { | ||
return this.element.progress(...arguments); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exposing the plugin property. |
||
|
||
renderAttachedBar = () => { | ||
return ( | ||
<div className='bar' /> | ||
); | ||
}; | ||
|
||
renderStandardBar = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've asked this before but I'm still a little fuzzy as to why we're not prefixing instance methods like this with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per Methods section of our fork of the Airbnb styleguide:
Keep in mind these are not classes that users instantiate and use their methods as with a traditional library. JSX handle the class instantiation and interaction is done by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More in depth here: airbnb/javascript#490 |
||
const label = ( | ||
<div className='label'> | ||
{this.props.children} | ||
</div> | ||
); | ||
|
||
return ( | ||
<div> | ||
<div className='bar'> | ||
<div className='progress'/> | ||
</div> | ||
{this.props.children && label} | ||
</div> | ||
); | ||
}; | ||
|
||
render() { | ||
const classes = classNames( | ||
'sd-progress', | ||
'ui', | ||
this.props.className, | ||
'progress', | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. configuring the classes. |
||
|
||
const isAttached = _.contains(this.props.className, 'attached'); | ||
return ( | ||
<div {...this.props} className={classes}> | ||
{isAttached ? this.renderAttachedBar() : this.renderStandardBar()} | ||
</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The markup as shown in semantic ui's documentation: http://semantic-ui.com/modules/progress.html#/definition There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like if there are children here they should be wrapped in a label <div className='lablel'>{this.props.children}</div> Make sure when there are no children there is not an empty label div present. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the <div className='ui segment'>
<div className='ui top attached progress'>
<div className='bar'></div>
</div>
</div> |
||
); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I felt like this was kind of messy, it was like, iteration number three though, so I decided to not waste anymore time and just try to get some feedback. Essentially just want to check if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In keeping with our style thus far (and removing the need for the bind operator) you can define the elements and conditions at the top of the render method. Then, use the conditions in the render() {
const isAttached = _.contains(this.props.className, 'attached');
const attachedBar = <div className='bar' />;
const label = (
<div className='label'>
{this.props.children}
</div>
);
const standardBar = (
<div>
<div className='bar'>
<div className='progress' />
</div>
{this.props.children && label}
</div>
);
const classes = classNames(
'sd-progress',
'ui',
this.props.className,
'progress',
);
return (
<div {...this.props} className={classes}>
{isAttached ? attachedBar : standardBar}
</div>
);
} EDIT There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually like how you broke those methods out though, then we aren't creating elements every render that we aren't using. We should really think about that moving forward. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ const jQueryPlugins = { | |
dropdown: sandbox.stub().returnsThis(), | ||
modal: sandbox.stub().returnsThis(), | ||
popup: sandbox.stub().returnsThis(), | ||
progress: sandbox.stub().returnsThis(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Studding out since Progress is a stardust module. |
||
transition: sandbox.stub().returnsThis(), | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
import {Progress} from 'stardust'; | ||
|
||
describe.only('Progress', () => { | ||
it('should be able to receive children', () => { | ||
render( | ||
<Progress> | ||
Child | ||
</Progress> | ||
).assertText('Child'); | ||
}); | ||
|
||
it('should create a div with the class of bar', () => { | ||
render(<Progress />).findClass('bar'); | ||
}); | ||
|
||
it('should create two progress divs if un-attached', () => { | ||
render(<Progress />) | ||
.scryClass('progress') | ||
.should.have.a.lengthOf(2); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Testing that it has a child with class of bar |
||
|
||
it('should not create extra progress div if attached', () => { | ||
render(<Progress className='attached' />) | ||
.scryClass('progress') | ||
.should.have.a.lengthOf(1); | ||
}); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checking that it has child with class of progress. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same testing notes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fyi - webpack/webpack-dev-server#334