diff --git a/docs/app/Components/ComponentDoc/ComponentProps.js b/docs/app/Components/ComponentDoc/ComponentProps.js index 0933c9ce74..3793afb1ec 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps.js +++ b/docs/app/Components/ComponentDoc/ComponentProps.js @@ -15,8 +15,8 @@ export default class ComponentProps extends Component { }; nameRenderer(item) { - const required = item.required && required; - return
{item.name} {required}
; + const required = item.required && ; + return {item.name} {required}; } defaultValueRenderer(item) { @@ -57,7 +57,7 @@ export default class ComponentProps extends Component { }); return ( - +

Props

diff --git a/docs/app/Examples/collections/Form/Content/FormContentExamples.js b/docs/app/Examples/collections/Form/Content/FormContentExamples.js new file mode 100644 index 0000000000..d6ab0b467c --- /dev/null +++ b/docs/app/Examples/collections/Form/Content/FormContentExamples.js @@ -0,0 +1,17 @@ +import React, {Component} from 'react'; +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'; +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'; + +export default class FormTypesExamples extends Component { + render() { + return ( + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/content/FormFieldExample.js b/docs/app/Examples/collections/Form/Content/FormFieldExample.js similarity index 100% rename from docs/app/Examples/collections/Form/content/FormFieldExample.js rename to docs/app/Examples/collections/Form/Content/FormFieldExample.js diff --git a/docs/app/Examples/collections/Form/FieldVariations/FormFieldInlineExample.js b/docs/app/Examples/collections/Form/FieldVariations/FormFieldInlineExample.js new file mode 100644 index 0000000000..2ca28ac828 --- /dev/null +++ b/docs/app/Examples/collections/Form/FieldVariations/FormFieldInlineExample.js @@ -0,0 +1,14 @@ +import React, {Component} from 'react'; +import {Field, Form, Input} from 'stardust'; + +export default class FormFieldInlineExample extends Component { + render() { + return ( +
+ + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/FieldVariations/FormFieldVariationsExamples.js b/docs/app/Examples/collections/Form/FieldVariations/FormFieldVariationsExamples.js new file mode 100644 index 0000000000..c94f50f5cc --- /dev/null +++ b/docs/app/Examples/collections/Form/FieldVariations/FormFieldVariationsExamples.js @@ -0,0 +1,17 @@ +import React, {Component} from 'react'; +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'; +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'; + +export default class FormFieldVariationsExamples extends Component { + render() { + return ( + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/FormExamples.js b/docs/app/Examples/collections/Form/FormExamples.js new file mode 100644 index 0000000000..a843b5c739 --- /dev/null +++ b/docs/app/Examples/collections/Form/FormExamples.js @@ -0,0 +1,22 @@ +import React, {Component} from 'react'; +import FormContentExamples from './Content/FormContentExamples'; +import FormTypesExamples from './Types/FormTypesExamples'; +import FormFieldVariationsExamples from './FieldVariations/FormFieldVariationsExamples'; +import FormGroupVariationsExamples from './GroupVariations/FormGroupVariationsExamples'; +import FormFormVariationsExamples from './FormVariations/FormFormVariationsExamples'; +import FormStatesExamples from './States/FormStatesExamples'; + +export default class FormExamples extends Component { + render() { + return ( +
+ + + + + + +
+ ); + } +} diff --git a/docs/app/Examples/collections/Form/FormVariations/FormFormVariationsExamples.js b/docs/app/Examples/collections/Form/FormVariations/FormFormVariationsExamples.js new file mode 100644 index 0000000000..b1475eff33 --- /dev/null +++ b/docs/app/Examples/collections/Form/FormVariations/FormFormVariationsExamples.js @@ -0,0 +1,20 @@ +import React, {Component} from 'react'; +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'; +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'; + +export default class FormFormVariationsExamples extends Component { + render() { + return ( + + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/FormVariations/FormSizeLargeExample.js b/docs/app/Examples/collections/Form/FormVariations/FormSizeLargeExample.js new file mode 100644 index 0000000000..0c5e64a96b --- /dev/null +++ b/docs/app/Examples/collections/Form/FormVariations/FormSizeLargeExample.js @@ -0,0 +1,20 @@ +import React, {Component} from 'react'; +import {Button, Field, Fields, Form, Input} from 'stardust'; + +export default class FormSizeLargeExample extends Component { + render() { + return ( +
+ + + + + + + + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/FormVariations/FormSizeSmallExample.js b/docs/app/Examples/collections/Form/FormVariations/FormSizeSmallExample.js new file mode 100644 index 0000000000..2cc87d8758 --- /dev/null +++ b/docs/app/Examples/collections/Form/FormVariations/FormSizeSmallExample.js @@ -0,0 +1,20 @@ +import React, {Component} from 'react'; +import {Button, Field, Fields, Form, Input} from 'stardust'; + +export default class FormSizeSmallExample extends Component { + render() { + return ( +
+ + + + + + + + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/GroupVariations/FormGroupEvenlyDividedExample.js b/docs/app/Examples/collections/Form/GroupVariations/FormGroupEvenlyDividedExample.js new file mode 100644 index 0000000000..aeb1d9214d --- /dev/null +++ b/docs/app/Examples/collections/Form/GroupVariations/FormGroupEvenlyDividedExample.js @@ -0,0 +1,19 @@ +import React, {Component} from 'react'; +import {Field, Fields, Form, Input} from 'stardust'; + +export default class FormGroupEvenlyDividedExample extends Component { + render() { + return ( +
+ + + + + + + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/GroupVariations/FormGroupVariationsExamples.js b/docs/app/Examples/collections/Form/GroupVariations/FormGroupVariationsExamples.js new file mode 100644 index 0000000000..d5e5086362 --- /dev/null +++ b/docs/app/Examples/collections/Form/GroupVariations/FormGroupVariationsExamples.js @@ -0,0 +1,17 @@ +import React, {Component} from 'react'; +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'; +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'; + +export default class FormGroupVariationsExamples extends Component { + render() { + return ( + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/FieldVariations/FormFieldErrorExample.js b/docs/app/Examples/collections/Form/States/FormFieldErrorExample.js similarity index 100% rename from docs/app/Examples/collections/Form/FieldVariations/FormFieldErrorExample.js rename to docs/app/Examples/collections/Form/States/FormFieldErrorExample.js diff --git a/docs/app/Examples/collections/Form/States/FormStatesExamples.js b/docs/app/Examples/collections/Form/States/FormStatesExamples.js new file mode 100644 index 0000000000..b1fe13c26a --- /dev/null +++ b/docs/app/Examples/collections/Form/States/FormStatesExamples.js @@ -0,0 +1,17 @@ +import React, {Component} from 'react'; +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'; +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'; + +export default class FormStatesExamples extends Component { + render() { + return ( + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/Types/FormFormExample.js b/docs/app/Examples/collections/Form/Types/FormFormExample.js new file mode 100644 index 0000000000..f1abe2fedf --- /dev/null +++ b/docs/app/Examples/collections/Form/Types/FormFormExample.js @@ -0,0 +1,21 @@ +import React, {Component} from 'react'; +import {Button, Checkbox, Field, Form, Input} from 'stardust'; + +export default class FormFieldExample extends Component { + render() { + return ( +
+ + + + + + + + + + + + ); + } +} diff --git a/docs/app/Examples/collections/Form/Types/FormTypesExamples.js b/docs/app/Examples/collections/Form/Types/FormTypesExamples.js new file mode 100644 index 0000000000..409eb77d03 --- /dev/null +++ b/docs/app/Examples/collections/Form/Types/FormTypesExamples.js @@ -0,0 +1,17 @@ +import React, {Component} from 'react'; +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'; +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'; + +export default class FormTypesExamples extends Component { + render() { + return ( + + + + ); + } +} diff --git a/karma.conf.js b/karma.conf.js index 31e3672dec..1d8d7ef1c4 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -13,7 +13,7 @@ export default config => { config.set({ browsers: ['PhantomJS'], singleRun: !ENV.isDevelopment(), - reporters: ['mocha'], + reporters: [ENV.isDevelopment() ? 'mocha' : 'dots'], files: [ './node_modules/phantomjs-polyfill/bind-polyfill.js', './test/tests.bundle.js' diff --git a/src/collections/Form/Fields.js b/src/collections/Form/Fields.js new file mode 100644 index 0000000000..21139eaf80 --- /dev/null +++ b/src/collections/Form/Fields.js @@ -0,0 +1,45 @@ +import _ from 'lodash'; +import React, {Children, Component, PropTypes} from 'react'; +import classNames from 'classnames'; +import getUnhandledProps from 'src/utils/getUnhandledProps'; +import numberToWord from 'src/utils/numberToWord'; +import META from 'src/utils/Meta.js'; + +export default class Fields extends Component { + static propTypes = { + children: PropTypes.node, + className: PropTypes.string, + /** + * Dynamically adds className=' fields'. + */ + evenlyDivided: PropTypes.bool, + }; + + static _meta = { + library: META.library.semanticUI, + name: 'Fields', + parent: 'Form', + type: META.type.collection, + }; + + render() { + let fieldCount = 0; + Children.forEach(this.props.children, child => { + _.get(child, 'type._meta.name') === 'Field' && fieldCount++; + }); + fieldCount = numberToWord(fieldCount); + + const classes = classNames( + 'sd-fields', + this.props.evenlyDivided && fieldCount, + this.props.className, + 'fields' + ); + const props = getUnhandledProps(this); + return ( +
+ {this.props.children} +
+ ); + } +} diff --git a/src/elements/Image/Image.js b/src/elements/Image/Image.js index 4e99ad9184..54d441cf6a 100644 --- a/src/elements/Image/Image.js +++ b/src/elements/Image/Image.js @@ -1,4 +1,3 @@ -import _ from 'lodash'; import React, {Component, PropTypes} from 'react'; import classNames from 'classnames'; import META from 'src/utils/Meta'; @@ -23,13 +22,10 @@ export default class Image extends Component { this.props.className, 'image' ); - const props = _.clone(this.props); - delete props.src; - delete props.alt; return ( -
- {this.props.alt} +
+
); } diff --git a/src/elements/Input/Input.js b/src/elements/Input/Input.js index 7cd27c32bf..c0e6be0da4 100644 --- a/src/elements/Input/Input.js +++ b/src/elements/Input/Input.js @@ -2,13 +2,12 @@ import _ from 'lodash'; import classNames from 'classnames'; import React, {Component, PropTypes, Children} from 'react'; import META from 'src/utils/Meta'; +import getUnhandledProps from 'src/utils/getUnhandledProps'; export default class Input extends Component { static propTypes = { children: PropTypes.node, className: PropTypes.string, - dataContent: PropTypes.string, - defaultValue: PropTypes.string, icon: PropTypes.string, ref: PropTypes.string, }; @@ -63,14 +62,13 @@ export default class Input extends Component { this.props.className, 'input' ); - const inputProps = _.clone(this.props); - delete inputProps.className; - delete inputProps.children; + const props = getUnhandledProps(this); + return (
{isLeftLabeled && labelChildren} {isLeftAction && actionChildren} - + {this.props.icon && icon} {isRightLabeled && labelChildren} {isRightAction && actionChildren} diff --git a/src/elements/List/List.js b/src/elements/List/List.js index 585ad64d3a..31ab66c4a5 100644 --- a/src/elements/List/List.js +++ b/src/elements/List/List.js @@ -4,6 +4,7 @@ import META from 'src/utils/Meta'; export default class List extends Component { static propTypes = { + children: PropTypes.node, className: PropTypes.string, }; @@ -16,7 +17,9 @@ export default class List extends Component { render() { const classes = classNames('sd-list', 'ui', this.props.className, 'list'); return ( -
+
+ {this.props.children} +
); } } diff --git a/src/index.js b/src/index.js index b0272b0fe2..958bc6c326 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import Textarea from 'src/addons/Textarea/Textarea'; // Collections import Column from 'src/collections/Grid/Column'; import Field from 'src/collections/Form/Field'; +import Fields from 'src/collections/Form/Fields'; import Form from 'src/collections/Form/Form'; import Grid from 'src/collections/Grid/Grid'; import Row from 'src/collections/Grid/Row'; @@ -43,6 +44,7 @@ export default { // Collections Column, Field, + Fields, Form, Grid, Row, diff --git a/src/modules/Dropdown/Dropdown.js b/src/modules/Dropdown/Dropdown.js index 340354a3a0..e8cac34da5 100644 --- a/src/modules/Dropdown/Dropdown.js +++ b/src/modules/Dropdown/Dropdown.js @@ -3,6 +3,7 @@ import $ from 'jquery'; import classNames from 'classnames'; import React, {Component, PropTypes} from 'react'; import META from 'src/utils/Meta'; +import getUnhandledProps from 'src/utils/getUnhandledProps'; export default class Dropdown extends Component { static propTypes = { @@ -43,8 +44,7 @@ export default class Dropdown extends Component { 'dropdown' ); - const props = _.clone(this.props); - delete props.options; + const props = getUnhandledProps(this); return ( ) .findTag('input') - .props.defaultValue.should.equal('John'); + .value.should.equal('John'); }); it('has a type of phone', () => { diff --git a/test/specs/modules/Dropdown/Dropdown-test.js b/test/specs/modules/Dropdown/Dropdown-test.js index b9ac769505..f15323b3d5 100644 --- a/test/specs/modules/Dropdown/Dropdown-test.js +++ b/test/specs/modules/Dropdown/Dropdown-test.js @@ -8,8 +8,9 @@ describe('Dropdown', () => { {value: 'admin', text: 'Admin'}, {value: 'editor', text: 'Editor'} ]; - const renderedDropdown = render().findTag('select'); - renderedDropdown.props.value.should.equal('admin'); + render() + .findTag('select') + .value.should.equal('admin'); }); it('has assigned amount of options', () => { const options = [ @@ -20,8 +21,11 @@ describe('Dropdown', () => { {value: 'purple', text: 'purple'}, {value: 'blue', text: 'blue'} ]; - const renderedDropdown = render(); - renderedDropdown.findTag('select').props.children.length.should.equal(6); - renderedDropdown.scryTag('option')[2].props.value.should.equal('green'); + render() + .scryTag('option') + .map((opt, i) => { + opt.text.should.equal(options[i].text); + opt.value.should.equal(options[i].value); + }); }); }); diff --git a/test/utils/getUnhandledPops-test.js b/test/utils/getUnhandledPops-test.js index df5507547e..99fa951414 100644 --- a/test/utils/getUnhandledPops-test.js +++ b/test/utils/getUnhandledPops-test.js @@ -10,24 +10,25 @@ class TestClass { } describe('getUnhandledProps', () => { - it('removes props defined in defaultProps', () => { - TestClass.defaultProps = {imHandled: 'thanks'}; - new TestClass() - .unhandledProps - .should.not.have.any.keys(_.keys(TestClass.defaultProps)); - }); it('removes props defined in propTypes', () => { - TestClass.propTypes = {imHandled: 'thanks'}; + TestClass.propTypes = {removeMe: 'thanks'}; new TestClass() .unhandledProps - .should.not.have.any.keys(_.keys(TestClass.defaultProps)); + .should.not.have.any.keys(_.keys(TestClass.propTypes)); }); - it('leave props not in defaultProps || propTypes in tact', () => { - TestClass.defaultProps = {imHandled: 'thanks'}; - TestClass.propTypes = {alsoHandled: 'got it'}; - const props = {thisShould: 'still be here'}; - new TestClass(props) - .unhandledProps - .should.eql(props); + it('leaves props if not defined in propTypes', () => { + const userProps = {leaveThis: 'because it is unhandled'}; + TestClass.propTypes = {removeMe: 'because we are handling it'}; + const unhandled = new TestClass(userProps).unhandledProps; + + unhandled.should.not.have.any.keys(_.keys(TestClass.propTypes)); + unhandled.should.have.all.keys(_.keys(userProps)); + }); + it('leaves propType props if also defined in defaultProps', () => { + TestClass.propTypes = {leaveMe: 'because it is also in defaultProps'}; + TestClass.defaultProps = {leaveMe: 'here i am'}; + const unhandled = new TestClass().unhandledProps; + + unhandled.should.have.all.keys(_.keys(TestClass.defaultProps)); }); });