All files / components/Checkbox Checkbox.jsx

100% Statements 12/12
83.33% Branches 5/6
100% Functions 0/0
100% Lines 12/12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150            134x   134x                       134x                                                                                       268x                 28x       9x                     40x   40x                                                                                                 16x   16x 16x 16x            
import _ from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import { lucidClassNames } from '../../util/style-helpers';
import { createClass, omitProps } from '../../util/component-types';
 
const cx = lucidClassNames.bind('&-Checkbox');
 
const { bool, func, object, string } = PropTypes;
 
/**
 * {"categories": ["controls", "toggles"]}
 *
 * This is a checkbox. It's a component that is in one of two particular states
 * at any given moment. It features a custom visualization of the native
 * checkbox button control to reflect its current state.
 *
 * It uses a hidden native checkbox control under the hood but leverages other
 * HTML elements to visualize its state.
 */
const Checkbox = createClass({
	displayName: 'Checkbox',
	propTypes: {
		/**
		 * Appended to the component-specific class names set on the root
		 * element.
		 */
		className: string,
 
		/**
		 * Indicates whether the component should appear in an "indeterminate"
		 * or "partially checked" state. This prop takes precedence over
		 * `isSelected`.
		 */
		isIndeterminate: bool,
 
		/**
		 * Indicates whether the component should appear and act disabled by
		 * having a "greyed out" palette and ignoring user interactions.
		 */
		isDisabled: bool,
 
		/**
		 * Indicates that the component is in the "selected" state when true
		 * and in the "unselected" state when false. This props is ignored if
		 * `isIndeterminate` is `true`.
		 */
		isSelected: bool,
 
		/**
		 * Called when the user clicks on the component or when they press the
		 * space key while the component is in focus.
		 *
		 * Signature: `(isSelected, { event, props }) => {}`
		 */
		onSelect: func,
 
		/**
		 * Passed through to the root element.
		 */
		style: object,
	},
 
	getDefaultProps() {
		return {
			isIndeterminate: false,
			isDisabled: false,
			isSelected: false,
			onSelect: _.noop,
		};
	},
 
	componentDidMount() {
		this.nativeElement = this.refs.nativeElement;
	},
 
	handleSpanClick(e) {
		e.preventDefault();
	},
 
	render() {
		const {
			className,
			isIndeterminate,
			isSelected,
			isDisabled,
			style,
			...passThroughs
		} = this.props;
 
		return (
			<div
				className={cx(
					'&',
					{
						'&-is-disabled': isDisabled,
						'&-is-selected': isIndeterminate || isSelected,
					},
					className
				)}
				onClick={this.handleClicked}
				style={style}
			>
				<input
					onChange={_.noop}
					{...omitProps(passThroughs, Checkbox, ['children'])}
					checked={isSelected}
					className={cx('&-native')}
					disabled={isDisabled}
					ref="nativeElement"
					type="checkbox"
				/>
				<span
					onClick={this.handleSpanClick}
					className={cx('&-visualization-glow')}
				/>
				<span
					onClick={this.handleSpanClick}
					className={cx('&-visualization-container')}
				/>
				{isIndeterminate
					? <span
							onClick={this.handleSpanClick}
							className={cx('&-visualization-indeterminate')}
						>
							<span className={cx('&-visualization-indeterminate-line')} />
						</span>
					: <span
							onClick={this.handleSpanClick}
							className={cx('&-visualization-checkmark')}
						>
							<span className={cx('&-visualization-checkmark-stem')} />
							<span className={cx('&-visualization-checkmark-kick')} />
						</span>}
			</div>
		);
	},
 
	handleClicked(event) {
		const { isDisabled, isSelected, onSelect } = this.props;
 
		Eif (!isDisabled) {
			onSelect(!isSelected, { event, props: this.props });
			this.nativeElement.focus();
		}
	},
});
 
export default Checkbox;