UNPKG

accessible-react-checkbox-group

Version:
345 lines (292 loc) 10.1 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: index.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: index.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>import React from 'react'; import PropTypes from 'prop-types'; export const CheckboxGroupContext = React.createContext(undefined); /** * @typedef {(string|number|boolean)} CheckboxValue */ /** * @typedef {Object} CheckboxOptions * @property {?boolean} checked - Whether or not the checkbox is checked. * @property {?boolean} indeterminate - Whether or not the checkbox is indeterminate. * @property {?Function} onChange - The function to call when the checkbox input changes state. */ /** * @typedef {Object} ExtractedContext * @property {string} name - The name of the checkbox group. * @property {CheckboxOptions} options - The natural attributes of a checkbox input. * @property {...*} props - Any additional props to pass to a checkbox input. */ /** * Extracts checkbox group context information for a given checkbox value into a normal props object. * * @param {{name: string, checkedValues: array.&lt;CheckboxValue>, indeterminateValues: array.&lt;CheckboxValue>, onChange: Function}} contextValue - The context information to extract. * @param {CheckboxValue} checkboxValue - The value of the checkbox to extract context for. * @param {object} props - Normal props to pass to the individual checkbox. * @returns {ExtractedContext} */ const extractContext = (contextValue, checkboxValue, props) => { // For some reason if we destructure values in the params hot reloading doesn't work const { name, checkedValues, indeterminateValues, onChange } = contextValue; const options = {}; if (checkedValues) { options.checked = checkedValues.indexOf(checkboxValue) >= 0; } if (indeterminateValues) { options.indeterminate = indeterminateValues.indexOf(checkboxValue) >= 0 ? true : undefined; } if (typeof onChange === 'function') { options.onChange = onChange.bind(null, checkboxValue); } return { name, options, ...props }; }; /** * A simple stateless functional component that renders a checkbox. * * @param {Object} props The props object for the component. * @param {CheckboxValue} props.value The value of the checkbox. * @param {boolean} props.indeterminate Whether or not the checkbox is indeterminate. * @param {...Object} props.restProps Any additional props for the checkbox input element. * @constructor */ const PreContextualizedCheckbox = ({ value, indeterminate, ...restProps }) => ( &lt;input aria-checked={indeterminate ? 'mixed' : restProps.checked.toString()} type="checkbox" ref={elem => { if (elem) { // eslint-disable-next-line no-param-reassign elem.indeterminate = indeterminate ? 'true' : undefined; } }} {...restProps} /> ); PreContextualizedCheckbox.defaultProps = { value: undefined, name: undefined, checked: false, indeterminate: undefined, onChange: undefined, }; PreContextualizedCheckbox.propTypes = { value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]), name: PropTypes.string, checked: PropTypes.bool, indeterminate: PropTypes.bool, onChange: PropTypes.func, }; export const Checkbox = props => ( &lt;CheckboxGroupContext.Consumer> {value => { const { name, options, ...rest } = extractContext(value, props.value, props); return ( &lt;PreContextualizedCheckbox name={name} checked={options.checked} indeterminate={options.indeterminate} onChange={options.onChange} {...rest} /> ); }} &lt;/CheckboxGroupContext.Consumer> ); Checkbox.defaultProps = { value: undefined, }; Checkbox.propTypes = { value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]), }; export class CheckboxGroup extends React.Component { state = { checkedValues: this.props.checkedValues, indeterminateValues: this.props.indeterminateValues, }; componentWillReceiveProps(newProps) { if (newProps.checkedValues) { this.setState({ checkedValues: newProps.checkedValues, }); } if (newProps.indeterminateValues) { this.setState({ indeterminateValues: newProps.indeterminateValues, }); } } isControlledComponent = () => Boolean(this.props.checkedValues); onCheckboxChange = (checkboxValue, event) => { let newValues; if (this.state.checkedValues.includes(checkboxValue)) { newValues = this.state.checkedValues.filter(v => v !== checkboxValue); } else { newValues = this.state.checkedValues.concat(checkboxValue); } if (this.isControlledComponent()) { this.setState({ checkedValues: this.props.checkedValues }); } else { this.setState({ checkedValues: newValues }); } if (typeof this.props.onChange === 'function') { this.props.onChange(newValues, event, this.props.name); } }; onCheckboxIndeterminate = (checkboxValue, event) => { let newValues; if (this.state.indeterminateValues.includes(checkboxValue)) { newValues = this.state.indeterminateValues.filter(v => v !== checkboxValue); } else { newValues = this.state.indeterminateValues.concat(checkboxValue); } if (this.isControlledComponent()) { this.setState({ indeterminateValues: this.props.indeterminateValues }); } else { this.setState({ indeterminateValues: newValues }); } if (typeof this.props.onIndeterminate === 'function') { this.props.onIndeterminate(newValues, event, this.props.name); } }; createChildren = (values, renderer, providedValue) => values.map((value, index) => { let checkboxValue = value; let props; let label; // value may be the direct value or an object with a value prop. if (typeof value === 'object') { checkboxValue = value.value; props = value.props ? value.props : {}; label = value.label ? value.label : checkboxValue; } const { name, options, ...rest } = extractContext(providedValue, checkboxValue, props); // label may be a function to return the label string or just the label string if (label &amp;&amp; {}.toString.call(label) === '[object Function]') { label = label(); } else if (!label) { label = checkboxValue; } const CheckboxComponent = ( &lt;PreContextualizedCheckbox key={[checkboxValue, index].join(' ')} name={name} checked={options.checked} indeterminate={options.indeterminate} onChange={options.onChange} {...rest} /> ); return renderer(CheckboxComponent, index, { label, value: checkboxValue, name, options, ...props, }); }); render() { const { Component, name, values, checkedValues, indeterminateValues, onChange, onIndeterminate, children, checkboxRenderer, ...rest } = this.props; const providedValue = { name, checkedValues, indeterminateValues, onChange: this.onCheckboxChange, toggleIndeterminate: this.onCheckboxIndeterminate, }; return ( &lt;CheckboxGroupContext.Provider value={providedValue}> &lt;Component {...rest}> {children || this.createChildren(values, checkboxRenderer, providedValue)} &lt;/Component> &lt;/CheckboxGroupContext.Provider> ); } } // Tbe shape of a checkbox value const valueShape = { value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]).isRequired, label: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), props: PropTypes.objectOf(PropTypes.any), }; valueShape.children = PropTypes.arrayOf(PropTypes.shape(valueShape)); CheckboxGroup.defaultProps = { name: undefined, values: [], checkedValues: [], indeterminateValues: [], onChange: undefined, onIndeterminate: undefined, children: undefined, Component: 'div', checkboxRenderer: (CheckboxComponent, index, { value, label }) => ( &lt;label key={[value, index].join(' ')}> {CheckboxComponent} {label} &lt;/label> ), }; CheckboxGroup.propTypes = { name: PropTypes.string, values: PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.bool, PropTypes.shape(valueShape), ]) ), // values: PropTypes.arrayOf(PropTypes.shape(valueShape)), checkedValues: PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]) ), indeterminateValues: PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]) ), onChange: PropTypes.func, onIndeterminate: PropTypes.func, children: PropTypes.node, Component: PropTypes.node, checkboxRenderer: PropTypes.func, }; </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="PreContextualizedCheckbox.html">PreContextualizedCheckbox</a></li></ul><h3>Global</h3><ul><li><a href="global.html#extractContext">extractContext</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Wed Jun 06 2018 14:47:34 GMT-0400 (Eastern Daylight Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>