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}
);
};