UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

273 lines 8.95 kB
import _noop from "lodash/noop"; import _isBoolean from "lodash/isBoolean"; import _isUndefined from "lodash/isUndefined"; import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { checkboxClasses as css, strings } from '@douyinfe/semi-foundation/lib/es/checkbox/constants'; import CheckboxFoundation from '@douyinfe/semi-foundation/lib/es/checkbox/checkboxFoundation'; import CheckboxInner from './checkboxInner'; import BaseComponent from '../_base/baseComponent'; import '@douyinfe/semi-foundation/lib/es/checkbox/checkbox.css'; import { Context } from './context'; import { getUuidShort } from '@douyinfe/semi-foundation/lib/es/utils/uuid'; class Checkbox extends BaseComponent { get adapter() { return Object.assign(Object.assign({}, super.adapter), { setNativeControlChecked: checked => { this.setState({ checked }); }, notifyChange: cbContent => { const { onChange } = this.props; onChange && onChange(cbContent); }, generateEvent: (checked, e) => { const { props } = this; const cbValue = { target: Object.assign(Object.assign({}, props), { checked }), stopPropagation: () => { e.stopPropagation(); }, preventDefault: () => { e.preventDefault(); }, nativeEvent: { stopImmediatePropagation: () => { if (e.nativeEvent && typeof e.nativeEvent.stopImmediatePropagation === 'function') { e.nativeEvent.stopImmediatePropagation(); } } } }; return cbValue; }, getIsInGroup: () => this.isInGroup(), getGroupValue: () => this.context && this.context.checkboxGroup.value || [], notifyGroupChange: cbContent => { this.context.checkboxGroup.onChange(cbContent); }, getGroupDisabled: () => this.context && this.context.checkboxGroup.disabled, setAddonId: () => { this.setState({ addonId: getUuidShort({ prefix: 'addon' }) }); }, setExtraId: () => { this.setState({ extraId: getUuidShort({ prefix: 'extra' }) }); }, setFocusVisible: focusVisible => { this.setState({ focusVisible }); }, focusCheckboxEntity: () => { this.focus(); } }); } constructor(props) { super(props); this.handleChange = e => this.foundation.handleChange(e); this.handleEnterPress = e => this.foundation.handleEnterPress(e); this.handleFocusVisible = event => { this.foundation.handleFocusVisible(event); }; this.handleBlur = event => { this.foundation.handleBlur(); }; const checked = false; this.state = { checked: props.checked || props.defaultChecked || checked, addonId: props.addonId, extraId: props.extraId, focusVisible: false }; this.checkboxEntity = null; this.foundation = new CheckboxFoundation(this.adapter); } componentDidUpdate(prevProps) { if (this.props.checked !== prevProps.checked) { if (_isUndefined(this.props.checked)) { this.foundation.setChecked(false); } else if (_isBoolean(this.props.checked)) { this.foundation.setChecked(this.props.checked); } } } isInGroup() { // Why do we need to determine whether there is a value in props? // If there is no value in the props of the checkbox in the context of the checkboxGroup, // it will be considered not to belong to the checkboxGroup。 return Boolean(this.context && this.context.checkboxGroup && 'value' in this.props); } focus() { this.checkboxEntity && this.checkboxEntity.focus(); } blur() { this.checkboxEntity && this.checkboxEntity.blur(); } render() { const { disabled, style, prefixCls, className, indeterminate, children, onMouseEnter, onMouseLeave, extra, value, role, tabIndex, id, type } = this.props; const { checked, addonId, extraId, focusVisible } = this.state; const props = { checked, disabled }; const inGroup = this.isInGroup(); if (inGroup) { if (this.context.checkboxGroup.value) { const realChecked = (this.context.checkboxGroup.value || []).includes(value); props.checked = realChecked; } if (this.context.checkboxGroup.disabled) { props.disabled = this.context.checkboxGroup.disabled || this.props.disabled; } const { isCardType, isPureCardType } = this.context.checkboxGroup; props.isCardType = isCardType; props.isPureCardType = isPureCardType; props['name'] = this.context.checkboxGroup.name; } else { props.isPureCardType = type === strings.TYPE_PURECARD; props.isCardType = type === strings.TYPE_CARD || props.isPureCardType; } const prefix = prefixCls || css.PREFIX; const focusOuter = props.isCardType || props.isPureCardType; const wrapper = classnames(prefix, { [`${prefix}-disabled`]: props.disabled, [`${prefix}-indeterminate`]: indeterminate, [`${prefix}-checked`]: props.checked, [`${prefix}-unChecked`]: !props.checked, [`${prefix}-cardType`]: props.isCardType, [`${prefix}-cardType_disabled`]: props.disabled && props.isCardType, [`${prefix}-cardType_enable`]: !(props.disabled && props.isCardType), [`${prefix}-cardType_checked`]: props.isCardType && props.checked && !props.disabled, [`${prefix}-cardType_checked_disabled`]: props.isCardType && props.checked && props.disabled, [className]: Boolean(className), [`${prefix}-focus`]: focusVisible && focusOuter }); const extraCls = classnames(`${prefix}-extra`, { [`${prefix}-cardType_extra_noChildren`]: props.isCardType && !children }); const name = inGroup && this.context.checkboxGroup.name; const xSemiPropChildren = this.props['x-semi-children-alias'] || 'children'; const renderContent = () => { if (!children && !extra) { return null; } return /*#__PURE__*/React.createElement("div", { className: `${prefix}-content` }, children ? (/*#__PURE__*/React.createElement("span", { id: addonId, className: `${prefix}-addon`, "x-semi-prop": xSemiPropChildren }, children)) : null, extra ? (/*#__PURE__*/React.createElement("div", { id: extraId, className: extraCls, "x-semi-prop": "extra" }, extra)) : null); }; return ( /*#__PURE__*/ // label is better than span, however span is here which is to solve gitlab issue #364 React.createElement("span", Object.assign({ role: role, tabIndex: tabIndex, style: style, className: wrapper, id: id, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onClick: this.handleChange, onKeyPress: this.handleEnterPress, "aria-labelledby": this.props['aria-labelledby'] }, this.getDataAttr(this.props)), /*#__PURE__*/React.createElement(CheckboxInner, Object.assign({}, this.props, props, { addonId: children && addonId, extraId: extra && extraId, isPureCardType: props.isPureCardType, ref: ref => { this.checkboxEntity = ref; }, focusInner: focusVisible && !focusOuter, onInputFocus: this.handleFocusVisible, onInputBlur: this.handleBlur })), renderContent()) ); } } Checkbox.contextType = Context; Checkbox.propTypes = { 'aria-describedby': PropTypes.string, 'aria-errormessage': PropTypes.string, 'aria-invalid': PropTypes.bool, 'aria-labelledby': PropTypes.string, 'aria-required': PropTypes.bool, // Specifies whether it is currently selected checked: PropTypes.bool, // Initial check defaultChecked: PropTypes.bool, // Failure state disabled: PropTypes.bool, // Set indeterminate state, only responsible for style control indeterminate: PropTypes.bool, // Callback function when changing onChange: PropTypes.func, value: PropTypes.any, style: PropTypes.object, className: PropTypes.string, prefixCls: PropTypes.string, onMouseEnter: PropTypes.func, onMouseLeave: PropTypes.func, extra: PropTypes.node, index: PropTypes.number, 'aria-label': PropTypes.string, tabIndex: PropTypes.number, preventScroll: PropTypes.bool, type: PropTypes.string }; Checkbox.defaultProps = { defaultChecked: false, indeterminate: false, onChange: _noop, onMouseEnter: _noop, onMouseLeave: _noop, type: 'default' }; Checkbox.elementType = 'Checkbox'; export default Checkbox;