import React, { ChangeEvent, FC, InputHTMLAttributes, Ref, useCallback, useEffect, useId, useContext, useRef, ReactNode, } from 'react'; import classnames from 'classnames'; import { FormElement } from './FormElement'; import { CheckboxGroupContext, CheckboxValueType } from './CheckboxGroup'; /** * */ export type CheckboxProps = { label?: string; required?: boolean; cols?: number; name?: string; value?: CheckboxValueType; checked?: boolean; defaultChecked?: boolean; indeterminate?: boolean; tooltip?: ReactNode; tooltipIcon?: string; elementRef?: Ref; inputRef?: Ref; } & InputHTMLAttributes; /** * */ export const Checkbox: FC = (props) => { const { type, // eslint-disable-line @typescript-eslint/no-unused-vars id: id_, className, label, required, cols, tooltip, tooltipIcon, elementRef, inputRef, indeterminate, onChange, children, ...rprops } = props; const prefix = useId(); const id = id_ ?? `${prefix}-id`; // `indeterminate` is a DOM-only property (no HTML attribute), // so we need an internal ref to set it imperatively while keeping `inputRef` working. const internalRef = useRef(null); const mergedRef = useCallback( (node: HTMLInputElement | null) => { (internalRef as React.MutableRefObject).current = node; if (typeof inputRef === 'function') { inputRef(node); } else if (inputRef) { (inputRef as React.MutableRefObject).current = node; } }, [inputRef] ); // Sync the DOM `indeterminate` property on mount and when the prop changes. useEffect(() => { if (internalRef.current) { internalRef.current.indeterminate = indeterminate === true; } }, [indeterminate]); // The browser resets the DOM `indeterminate` property to `false` on every click, // so we re-apply it after the consumer's onChange handler runs. const handleChange = useCallback( (e: ChangeEvent) => { onChange?.(e); if (internalRef.current) { internalRef.current.indeterminate = indeterminate === true; } }, [onChange, indeterminate] ); const { grouped, error, errorId } = useContext(CheckboxGroupContext); const formElemProps = { required, error, errorId, cols, tooltip, tooltipIcon, elementRef, }; const checkClassNames = classnames(className, 'slds-checkbox'); const check = (
); return grouped ? ( check ) : ( {check} ); };