diff --git a/demo/Demo.react.js b/demo/Demo.react.js index d34e24c05..385c733ec 100644 --- a/demo/Demo.react.js +++ b/demo/Demo.react.js @@ -268,7 +268,6 @@ const ChecklistExample = ` const properties = { id: 'my checklist', labelStyle: {'display': 'block'}, - disabled: false, options: [ {'label': 'Melons', 'value': 'melons', 'disabled': false}, {'label': 'Apples', 'value': 'apples'}, @@ -299,6 +298,54 @@ class Controller extends Component { ReactDOM.render(, mountNode);` +const ChecklistContainerExample = ` +const applesDescription = (
+

Apples.jpg

+

This option selects the best and most fancy apples in the world

+
); + +const orangesDescription = (

There is no oranges available. Please come back in oranges season.

); + +const properties = { + id: 'my container checklist', + labelStyle: {'display': 'block'}, + options: [ + {'label': 'Melons', 'value': 'melons', 'disabled': false}, + {'label': 'Apples', 'value': 'apples', + 'children': applesDescription, + 'collapseChildrenButton': true, + 'initiallyExpanded': false + }, + {'label': 'Oranges', 'value': 'oranges', 'disabled': true, + 'children': orangesDescription, + 'collapseChildrenButton': true, + 'initiallyExpanded': true} + ] +}; + +class Controller extends Component { + constructor() { + super(); + this.state = { + values: ['melons', 'apples'] + }; + } + + render() { + return ( { + this.setState(props); + }} + fireEvent={event => console.warn(event)} + values={this.state.values} + {...properties} + />); + } +} + +ReactDOM.render(, mountNode);` + + const examples = [ {name: 'Upload', code: UploadExample}, @@ -308,6 +355,7 @@ const examples = [ {name: 'SyntaxHighlighter', code: SyntaxHighlighterExample}, {name: 'Radio', code: RadioExample}, {name: 'Checklist', code: ChecklistExample}, + {name: 'Checklist with containers options', code: ChecklistContainerExample}, {name: 'Dropdown', code: DropdownExample}, {name: 'Slider', code: SliderExample}, {name: 'RangeSlider', code: RangeSliderExample}, diff --git a/src/components/Checklist.react.js b/src/components/Checklist.react.js index 1c921ac4b..246f06b1d 100644 --- a/src/components/Checklist.react.js +++ b/src/components/Checklist.react.js @@ -1,6 +1,135 @@ -import {append, contains, without} from 'ramda'; +import {append, contains, without} from 'ramda'; import React, {Component, PropTypes} from 'react'; +class Checkbox extends Component { + + constructor(props) { + super(props); + + if (props.collapsable) { + this.state = { + collapsed: props.initiallyExpanded + }; + this.handleCollapseClick = this.handleCollapseClick.bind(this); + } + } + + handleCollapseClick() { + this.setState({ collapsed: !this.state.collapsed }); + } + + render() { + + const { + children, + collapsable, + disabled, + inputClassName, + inputStyle, + isChecked, + label, + labelClassName, + labelStyle, + value + } = this.props; + + + let arrow; + let CollapsableChildren; + + if (collapsable) { + const collapsed = this.state.collapsed; + arrow = ( +
+ {collapsed? '▾' : '▴'} +
+ ); + + CollapsableChildren = ( +
+ {collapsed ? null : children} +
+ ); + } + + return ( +
+
+ + {collapsable? arrow : null} +
+ + {collapsable? CollapsableChildren : children} +
+ ); + } +} + +Checkbox.propTypes = { + /** + * The checkbox's label + */ + label: PropTypes.string, + + /** + * The value of the checkbox. This value + * corresponds to the items specified in the + * `values` property. + */ + value: PropTypes.string, + + /** + * If true, this checkbox is disabled and can't be clicked on. + */ + disabled: PropTypes.bool, + + + /** + * Optinal wrapped components within this option + */ + children: PropTypes.node, + + /** + * Show a button to show/hide children components of this option + */ + collapsable: PropTypes.bool, + + /** + * Change default for the initiallyExpanded to be initially collapsed (hidden) + */ + initiallyExpanded: PropTypes.bool, + + /** + * Mark if the input is checked or not + */ + checked: PropTypes.bool, + + /** + * Callback to the parent to add or remove this option from the Checklist + */ + handleOnChange: PropTypes.func +} + +Checkbox.defaultProps = { + initiallyExpanded: true +} + /** * Checklist is a component that encapsulates several checkboxes. * The values and labels of the checklist is specified in the `options` @@ -11,56 +140,56 @@ export default class Checklist extends Component { constructor(props) { super(props); this.state = {values: props.values}; + + this.handleOnChange = this.handleOnChange.bind(this); } componentWillReceiveProps(newProps) { this.setState({values: newProps.values}); } + handleOnChange(value) { + const values = this.state.values; + let newValues; + if (contains(value, values)) { + newValues = without([value], values); + } else { + newValues = append(value, values); + } + this.setState({values: newValues}); + + const {fireEvent, setProps} = this.props; + if (setProps) setProps({values: newValues}); + if (fireEvent) fireEvent({event: 'change'}); + } + render() { const { className, - fireEvent, id, - inputClassName, - inputStyle, - labelClassName, - labelStyle, options, - setProps, - style + style, + values, + ...rest } = this.props; - const {values} = this.state; return (
{options.map(option => ( - - ))} + + ) + )}
); } @@ -72,24 +201,42 @@ Checklist.propTypes = { /** * An array of options */ - options: PropTypes.shape({ - /** - * The checkbox's label - */ - label: PropTypes.string, - - /** - * The value of the checkbox. This value - * corresponds to the items specified in the - * `values` property. - */ - value: PropTypes.string, - - /** - * If true, this checkbox is disabled and can't be clicked on. - */ - disabled: PropTypes.bool - }), + options: PropTypes.arrayOf( + PropTypes.shape({ + /** + * The checkbox's label + */ + label: PropTypes.string, + + /** + * The value of the checkbox. This value + * corresponds to the items specified in the + * `values` property. + */ + value: PropTypes.string, + + /** + * If true, this checkbox is disabled and can't be clicked on. + */ + disabled: PropTypes.bool, + + /** + * Optinal wrapped components within this option + */ + children: PropTypes.node, + + /** + * Show a button to show/hide children components of this option + */ + collapseChildrenButton: PropTypes.bool, + + /** + * Change default for the collapseChildrenButton to be initially hidden + */ + initiallyExpanded: PropTypes.bool + + }) + ), /** * The currently selected value diff --git a/src/components/__tests__/Checklist.test.js b/src/components/__tests__/Checklist.test.js new file mode 100644 index 000000000..fcbc7c57f --- /dev/null +++ b/src/components/__tests__/Checklist.test.js @@ -0,0 +1,15 @@ +import React from 'react'; +import {shallow} from 'enzyme'; +import CheckListComponent from '../Checklist.react'; + +describe('Checklist component', () => { + + it('renders', () => { + const component = shallow(); + expect(component).to.be.ok; + }); + + describe('options', () => { + it('renders passed-in options'); + }); +});