import React, { useContext, forwardRef, Ref, LabelHTMLAttributes } from "react"; import classNames from "classnames"; import { useRefAndForward } from "../_util/use-ref-and-forward"; import { WithoutMethod, Omit } from "../_type"; import { ControlledProps, ChangeContext, useDefaultValue, } from "../form/controlled"; import { Tooltip } from "../tooltip"; import { callBoth } from "../_util/call-both"; import { useConfig } from "../_util/config-context"; import { useIsomorphicLayoutEffect } from "../_util/use-isomorphic-layout-effect"; /** * `CheckInput` 组件所接收的参数 */ export interface CheckProps extends ControlledProps, Omit, "onChange" | "defaultValue"> { /** * 获取内部 `input` 的引用 */ inputRef?: React.Ref; /** * 名称,对于使用 `CheckGroup` 等管理时必传 */ name?: string; /** * 选项类型 */ type: "radio" | "checkbox"; /** * 默认是否已经勾选 */ defaultValue?: boolean; /** * 是否已经勾选 */ value?: boolean; /** * 勾选状态发生变更时回调 */ onChange?: (value: boolean, context: CheckChangeContext) => void; /** * 是否半选状态(仅对 `checkbox` 生效) * @default false */ indeterminate?: boolean; /** * 是否可用 * @default false */ disabled?: boolean; /** * 渲染方式,设置为 `block` 会独占一行 * @default "inline" */ display?: "inline" | "block"; /** 文本解释内容,可用于解释选项的作用 */ tooltip?: React.ReactNode; /** 点击时触发 */ onClick?: (event: React.MouseEvent) => void; } /** * 为变更事件提供额外的内容 */ export interface CheckChangeContext extends ChangeContext { /** * 发生变化的选项组件实例 */ check: ReadonlyCheckProps; } /** * 组件实例只读属性集合 */ export interface ReadonlyCheckProps extends Readonly> {} /** * Check 组件支持使用 CheckContext 进行状态托管 */ export const CheckContext = React.createContext(null); /** * 托管 Check 组件的状态,请提供 inject() 方法注入托管好的 props */ export interface CheckContextValue { inject: (props: CheckProps) => CheckProps; } export const Check = forwardRef( (_props: CheckProps, ref: Ref) => { const { classPrefix } = useConfig(); // 支持从 Context 注入 const context = useContext(CheckContext); let props = _props; if (context) { props = context.inject(_props); } const { value, onChange, type, indeterminate, children, className, disabled = false, onClick, display, style = {}, inputRef, tooltip, tabIndex, ...htmlProps } = useDefaultValue(props, false); // handle indeterminate const [checkInputRef, forwardInputRef] = useRefAndForward(null, inputRef); useIsomorphicLayoutEffect(() => { if (type === "checkbox" && checkInputRef.current) { checkInputRef.current.indeterminate = indeterminate; } }); const labelClassName = classNames( `${classPrefix}-form-check`, { [`${classPrefix}-form-check--block`]: display === "block", }, className ); const input = ( ) => onChange(event.currentTarget.checked, { event, check: { ...props, value: event.currentTarget.checked }, }) )} /> ); let check = ( ); if (tooltip) { check = {check}; } return check; } ); Check.displayName = "Check";