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          120x             120x                       120x                                                                                       120x                 43x       9x                     55x   55x                                                                                 31x   31x 31x 31x            
import _ from 'lodash';
import React from 'react';
import { lucidClassNames } from '../../util/style-helpers';
import { createClass, omitProps } from '../../util/component-types';
 
const cx = lucidClassNames.bind('&-Checkbox');
 
const {
	bool,
	func,
	object,
	string,
} = React.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}
				onTouchEnd={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>
				) : (
					<span onClick={this.handleSpanClick} className={cx('&-visualization-checkmark')}>
						<span className={cx('&-visualization-checkmark-stem')}></span>
						<span className={cx('&-visualization-checkmark-kick')}></span>
					</span>
				)
				}
			</div>
		);
	},
 
	handleClicked(event) {
		const {
			isDisabled,
			isSelected,
			onSelect,
		} = this.props;
 
		Eif (!isDisabled) {
			onSelect(!isSelected, { event, props: this.props });
			this.nativeElement.focus();
		}
	},
});
 
export default Checkbox;