UNPKG

@shopify/polaris

Version:

Shopify’s product component library

72 lines (71 loc) 3.13 kB
import React, { useRef, useImperativeHandle } from 'react'; import { MinusMinor, TickSmallMinor } from '@shopify/polaris-icons'; import { useUniqueId } from '../../utilities/unique-id'; import { classNames } from '../../utilities/css'; import { Choice, helpTextID } from '../Choice'; import { errorTextID } from '../InlineError'; import { Icon } from '../Icon'; import { Key } from '../../types'; import styles from './Checkbox.scss'; export const Checkbox = React.forwardRef(function Checkbox({ ariaDescribedBy: ariaDescribedByProp, label, labelHidden, checked = false, helpText, disabled, id: idProp, name, value, error, onChange, onFocus, onBlur, }, ref) { const inputNode = useRef(null); const id = useUniqueId('Checkbox', idProp); useImperativeHandle(ref, () => ({ focus: () => { if (inputNode.current) { inputNode.current.focus(); } }, })); const handleInput = () => { if (onChange == null || inputNode.current == null || disabled) { return; } onChange(!inputNode.current.checked, id); inputNode.current.focus(); }; const handleKeyUp = (event) => { const { keyCode } = event; if (keyCode !== Key.Space) return; handleInput(); }; const describedBy = []; if (error && typeof error !== 'boolean') { describedBy.push(errorTextID(id)); } if (helpText) { describedBy.push(helpTextID(id)); } if (ariaDescribedByProp) { describedBy.push(ariaDescribedByProp); } const ariaDescribedBy = describedBy.length ? describedBy.join(' ') : undefined; const wrapperClassName = classNames(styles.Checkbox, error && styles.error); const isIndeterminate = checked === 'indeterminate'; const isChecked = !isIndeterminate && Boolean(checked); const indeterminateAttributes = isIndeterminate ? { indeterminate: 'true', 'aria-checked': 'mixed' } : { 'aria-checked': isChecked }; const iconSource = isIndeterminate ? MinusMinor : TickSmallMinor; const inputClassName = classNames(styles.Input, isIndeterminate && styles['Input-indeterminate']); return ( /* eslint-disable jsx-a11y/no-redundant-roles */ <Choice id={id} label={label} labelHidden={labelHidden} helpText={helpText} error={error} disabled={disabled} onClick={handleInput}> <span className={wrapperClassName}> <input onKeyUp={handleKeyUp} ref={inputNode} id={id} name={name} value={value} type="checkbox" checked={isChecked} disabled={disabled} className={inputClassName} onFocus={onFocus} onBlur={onBlur} onClick={stopPropagation} onChange={noop} aria-invalid={error != null} aria-describedby={ariaDescribedBy} role="checkbox" {...indeterminateAttributes}/> <span className={styles.Backdrop}/> <span className={styles.Icon}> <Icon source={iconSource}/> </span> </span> </Choice> /* eslint-enable jsx-a11y/no-redundant-roles */ ); }); function noop() { } function stopPropagation(event) { event.stopPropagation(); }