/* eslint-disable max-len */ /* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */ import React, { forwardRef, useContext, useRef, useState } from "react" import PropTypes from "prop-types" import classNames from "classnames" import { GroupContext } from "./Context" import Group from "./Group" import Icon, { IconNames } from "../icon" import Popover, { IPopoverProps } from "../popover" import { ConfigContext, getComputedSize } from "../config-provider" import { useActive } from "../_util/hooks/use-active" import "./style" const prefix = "adui-checkbox" export interface ICheckboxProps { [key: string]: any /** * 是否选中 */ checked?: null | boolean /** * 子节点 */ children?: React.ReactNode /** * 附加类名 */ className?: string /** * 是否禁用 */ disabled?: boolean /** * 加入问号气泡提示内容 */ helper?: React.ReactNode /** * 自定义问号气泡的 Icon */ helperIcon?: IconNames /** * 问号气泡提示的 props,会将此对象都传递给 */ helperProps?: IPopoverProps /** * 设置 indeterminate 状态,负责且仅仅负责样式控制,请在实现全选效果时使用 */ indeterminate?: boolean /** * 选中态发生变化时的 handler */ onChange?: ((checked: boolean) => void) | null /** * 点击时的 handler */ onClick?: | (( e: | React.MouseEvent | React.KeyboardEvent ) => void) | null /** * onMouseDown 时的 handler */ onMouseDown?: (e: React.MouseEvent) => void /** * 设置尺寸 */ size?: "mini" | "small" | "medium" | "large" /** * 值,只在使用 Checkbox.Group 时会读取使用 */ value?: null | React.ReactText } export interface ICheckbox extends React.ForwardRefExoticComponent< ICheckboxProps & React.RefAttributes > { Group: typeof Group } /** * 勾选提供用户在多个选项中,对选项的内容进行单或多个选择。 */ // @ts-ignore const Checkbox: ICheckbox = forwardRef( ( { checked: checkedProp, children, className, disabled, helper, helperIcon, helperProps, indeterminate, onChange, onClick, onMouseDown, size: sizeProp, value, ...otherProps }: ICheckboxProps, refProp ) => { const [checked, setChecked] = useState(!!checkedProp) const { disabled: disabledContext, handleGroupValueChange, size: sizeContext, value: valueContext, } = useContext(GroupContext) const { size: sizeConfig } = useContext(ConfigContext) const labelRef = useRef(null) const ref = refProp || labelRef const { handleMouseDown } = useActive({ ref }) // 相当于生命周期 getDerivedStateFromProps if (checkedProp !== null && checked !== !!checkedProp) { setChecked(!!checkedProp) } const size = getComputedSize(sizeProp, sizeContext, sizeConfig) const valueComputed = value !== null ? value : children?.toString() /** * 当有 context context 时,使用 value: * 如果存在 value prop,则直接使用 value; * 如果不存在,就 string 化 children 作为 value。 */ const classSet = classNames( className, `${prefix}-base`, `${prefix}-${size}`, { [`${prefix}-checked`]: indeterminate || (valueContext ? valueComputed !== null && valueComputed !== undefined && valueContext.includes(valueComputed) : checked), [`${prefix}-noChildren`]: !children, [`${prefix}-disabled`]: disabledContext || disabled, [`${prefix}-indeterminate`]: indeterminate, } ) const popover = helper ? ( { e.stopPropagation() }} > ) : null const handleClick = ( e: | React.MouseEvent | React.KeyboardEvent ) => { if (onClick) { onClick(e) } if (disabled || disabledContext) { return } if ( handleGroupValueChange && valueComputed !== null && valueComputed !== undefined ) { handleGroupValueChange(valueComputed) } else { if (checkedProp === null) { setChecked(!checked) } if (onChange) { onChange(!checked) } } } const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter") { handleClick(e) } } const handleLabelMouseDown = ( e: React.MouseEvent ) => { if (onMouseDown) { onMouseDown(e) } handleMouseDown() } return ( ) } ) Checkbox.Group = Group Checkbox.displayName = "Checkbox" Checkbox.propTypes = { /** * 是否选中 */ checked: PropTypes.oneOf([null, true, false]), /** * 子节点 */ children: PropTypes.node, /** * 附加类名 */ className: PropTypes.string, /** * 是否禁用 */ disabled: PropTypes.bool, /** * 加入问号气泡提示内容 */ helper: PropTypes.node, /** * 自定义问号气泡的 Icon */ helperIcon: PropTypes.any, /** * 问号气泡提示的 props,会将此对象都传递给 */ helperProps: PropTypes.object, /** * 设置 indeterminate 状态,负责且仅仅负责样式控制,请在实现全选效果时使用 */ indeterminate: PropTypes.bool, /** * 选中态发生变化时的 handler */ onChange: PropTypes.func, /** * 点击时的 handler */ onClick: PropTypes.func, /** * 设置尺寸 */ size: PropTypes.oneOf(["mini", "small", "medium", "large"]), /** * 值,只在使用 Checkbox.Group 时会读取使用 */ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), } Checkbox.defaultProps = { checked: null, children: "", className: undefined, disabled: false, helper: null, helperIcon: "help-circle", helperProps: {}, indeterminate: false, onChange: null, onClick: null, size: "small", value: null, } export default Checkbox