wix-style-react
Version:
233 lines (204 loc) • 6.85 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import CheckboxChecked from 'wix-ui-icons-common/system/CheckboxChecked';
import CheckboxIndeterminate from 'wix-ui-icons-common/system/CheckboxIndeterminate';
import { st, classes } from './Checkbox.st.css';
import Text from '../Text';
import { withFocusable } from 'wix-ui-core/dist/src/hocs/Focusable/FocusableHOC';
import deprecationLog from '../utils/deprecationLog';
import { generateID } from '../utils/generateId';
import Tooltip from '../Tooltip';
import * as DATA_ATTR from './DataAttr';
import { dataHooks } from './constants';
import { TooltipCommonProps } from '../common/PropTypes/TooltipCommon';
/** a simple WixStyle checkbox */
class Checkbox extends React.PureComponent {
// TODO fix me please. We need to get away from ids.
_id = `${Checkbox.displayName}-${generateID()}`;
checkboxRef = React.createRef();
focus = () => {
this.checkboxRef.current && this.checkboxRef.current.focus();
};
_getDataAttributes = () => {
const { checked, indeterminate, disabled, hasError } = this.props;
return {
[DATA_ATTR.DATA_CHECK_TYPE]: indeterminate
? DATA_ATTR.CHECK_TYPES.INDETERMINATE
: checked
? DATA_ATTR.CHECK_TYPES.CHECKED
: DATA_ATTR.CHECK_TYPES.UNCHECKED,
[DATA_ATTR.DATA_HAS_ERROR]: hasError && !disabled,
[DATA_ATTR.DATA_DISABLED]: disabled,
};
};
render() {
const {
id = this._id,
checked,
indeterminate,
disabled,
hasError,
errorMessage,
selectionArea,
vAlign,
size,
onChange,
children,
dataHook,
focusableOnFocus,
focusableOnBlur,
className,
tooltipProps,
tooltipContent,
selectionAreaSkin,
selectionAreaPadding,
} = this.props;
if (errorMessage) {
deprecationLog(
'<Checkbox/> - errorMessage prop is deprecated and will be removed in next major release, please use tooltipContent instead',
);
}
const isTooltipDisabled =
(tooltipProps && tooltipProps.disabled) ||
disabled ||
(!tooltipContent && (!hasError || !errorMessage));
return (
<div
data-hook={dataHook}
className={st(
classes.root,
{
vAlign,
selectionArea,
selectionAreaSkin,
disabled,
error: hasError && !disabled,
selection: indeterminate
? 'indeterminate'
: checked
? 'checked'
: 'unchecked',
indeterminate,
},
className,
)}
onFocus={focusableOnFocus}
onBlur={focusableOnBlur}
tabIndex={disabled ? null : 0}
{...this._getDataAttributes()}
role="checkbox"
aria-checked={checked}
ref={this.checkboxRef}
>
<input
data-hook={dataHooks.input}
type="checkbox"
id={id}
checked={checked}
disabled={disabled}
onChange={disabled ? null : onChange}
style={{ display: 'none' }}
/>
<label
htmlFor={id}
data-hook={dataHooks.label}
className={classes.label}
>
<div
className={classes.labelInner}
style={{ padding: selectionAreaPadding }}
>
<Tooltip
dataHook={dataHooks.boxTooltip}
disabled={isTooltipDisabled}
content={tooltipContent || errorMessage || ' '}
textAlign="center"
maxWidth={230}
hideDelay={150}
zIndex={10000}
{...tooltipProps}
>
<div className={classes.outer}>
<div data-hook={dataHooks.box} className={classes.checkbox}>
<div
className={classes.inner}
onClick={e => e.stopPropagation()}
>
{indeterminate ? (
<CheckboxIndeterminate />
) : (
<CheckboxChecked />
)}
</div>
</div>
</div>
</Tooltip>
{children && (
<Text
size={size}
onClick={e => e.stopPropagation()}
weight="thin"
dataHook={dataHooks.children}
className={classes.children}
>
{children}
</Text>
)}
</div>
</label>
</div>
);
}
}
Checkbox.displayName = 'Checkbox';
Checkbox.propTypes = {
/** Applies a data-hook HTML attribute that can be used in tests */
dataHook: PropTypes.string,
/** Specifies whether a checkbox is selected */
checked: PropTypes.bool,
/** Renders any component passed within <Checkbox> tags as the label of a checkbox. The default value is a text string. */
children: PropTypes.node,
/** Specifies whether a checkbox is disabled */
disabled: PropTypes.bool,
/** Specifies whether a checkbox has an error */
hasError: PropTypes.bool,
/** Assigns a unique identifier for the checkbox */
id: PropTypes.string,
/** Specifies whether a checkbox is in an indeterminate state */
indeterminate: PropTypes.bool,
/**
* The error message when there's an error
* @deprecated
* */
errorMessage: PropTypes.string,
/** Controls the selection area highlight visibility */
selectionArea: PropTypes.oneOf(['none', 'hover', 'always']),
/** Controls checkbox alignment to the label on the Y axis */
vAlign: PropTypes.oneOf(['center', 'top']),
/** Controls the size of the checkbox label */
size: PropTypes.oneOf(['small', 'medium']),
/** Defines a callback function which is called every time the checkbox state is changed */
onChange: PropTypes.func,
/** Specifies a CSS class name to be appended to the component’s root element */
className: PropTypes.string,
/** Sets the design of the selection area */
selectionAreaSkin: PropTypes.oneOf(['filled', 'outlined']),
/** Sets the amount of white space around the checkbox label in pixels */
selectionAreaPadding: PropTypes.string,
/** Defines a message to be displayed in a tooltip. Tooltip is displayed on a checkbox hover. */
tooltipContent: PropTypes.node,
/** Allows you to pass all common tooltip props. Check `<Tooltip/>` for the full API. */
tooltipProps: PropTypes.shape(TooltipCommonProps),
};
Checkbox.defaultProps = {
checked: false,
size: 'medium',
selectionArea: 'none',
vAlign: 'center',
onChange: e => e.stopPropagation(),
hasError: false,
disabled: false,
indeterminate: false,
selectionAreaSkin: 'filled',
};
export default withFocusable(Checkbox);