@shopify/polaris
Version:
Shopify’s admin product component library
144 lines (129 loc) • 4.09 kB
JavaScript
import React, { forwardRef, useRef, useState, useContext, useImperativeHandle } from 'react';
import { MinusMinor, TickSmallMinor } from '@shopify/polaris-icons';
import { classNames } from '../../utilities/css.js';
import { useToggle } from '../../utilities/use-toggle.js';
import { Key } from '../../types.js';
import { WithinListboxContext } from '../../utilities/listbox/context.js';
import styles from './Checkbox.scss.js';
import { Choice, helpTextID } from '../Choice/Choice.js';
import { errorTextID } from '../InlineError/InlineError.js';
import { useUniqueId } from '../../utilities/unique-id/hooks.js';
import { Icon } from '../Icon/Icon.js';
const Checkbox = /*#__PURE__*/forwardRef(function Checkbox({
ariaControls,
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);
const {
value: mouseOver,
setTrue: handleMouseOver,
setFalse: handleMouseOut
} = useToggle(false);
const [keyFocused, setKeyFocused] = useState(false);
const isWithinListbox = useContext(WithinListboxContext);
useImperativeHandle(ref, () => ({
focus: () => {
if (inputNode.current) {
inputNode.current.focus();
}
}
}));
const handleBlur = () => {
onBlur && onBlur();
setKeyFocused(false);
};
const handleKeyUp = event => {
const {
keyCode
} = event;
if (keyCode === Key.Space || keyCode === Key.Tab) {
!keyFocused && setKeyFocused(true);
}
};
const handleOnClick = () => {
if (onChange == null || inputNode.current == null || disabled) {
return;
}
onChange(inputNode.current.checked, id);
inputNode.current.focus();
};
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 backdropClassName = classNames(styles.Backdrop, mouseOver && styles.hover);
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'], keyFocused && styles.keyFocused);
return /*#__PURE__*/React.createElement(Choice, {
id: id,
label: label,
labelHidden: labelHidden,
helpText: helpText,
error: error,
disabled: disabled,
onMouseOver: handleMouseOver,
onMouseOut: handleMouseOut
}, /*#__PURE__*/React.createElement("span", {
className: wrapperClassName
}, /*#__PURE__*/React.createElement("input", Object.assign({
ref: inputNode,
id: id,
name: name,
value: value,
type: "checkbox",
checked: isChecked,
disabled: disabled,
className: inputClassName,
onBlur: handleBlur,
onChange: noop,
onClick: handleOnClick,
onFocus: onFocus,
onKeyUp: handleKeyUp,
"aria-invalid": error != null,
"aria-controls": ariaControls,
"aria-describedby": ariaDescribedBy,
role: isWithinListbox ? 'presentation' : 'checkbox'
}, indeterminateAttributes)), /*#__PURE__*/React.createElement("span", {
className: backdropClassName,
onClick: stopPropagation,
onKeyUp: stopPropagation
}), /*#__PURE__*/React.createElement("span", {
className: styles.Icon
}, /*#__PURE__*/React.createElement(Icon, {
source: iconSource
}))));
});
function noop() {}
function stopPropagation(event) {
event.stopPropagation();
}
export { Checkbox };