import classnames from "classnames"; import React, { createContext, useContext, useEffect, useMemo } from "react"; interface CheckboxGroupContext { values: T[]; onChange: (checked: boolean, value: T) => void; disabled?: boolean; } const CheckboxGroupContext = createContext>({ values: [], onChange: (checked, value) => {}, }); const useCheckboxGroupContext = () => useContext(CheckboxGroupContext); export const CheckboxIndicator = ({ status, className, }: { status: boolean; className?: string; }) => { if (status) { return ( ); } else { return ( ); } }; interface CheckboxProps { children: | string | React.ReactElement | ((checked?: boolean) => React.ReactElement); checked?: boolean; onChange?: (checked: boolean) => void; customIndicator?: | React.ReactElement | ((checked?: boolean) => React.ReactElement); disabled?: boolean; value?: T; } export const Checkbox = ({ children, checked, disabled, value, onChange, customIndicator, }: CheckboxProps) => { const groupContext = useCheckboxGroupContext(); const { values, onChange: groupOnChange, disabled: groupDisabled, } = groupContext; const status = useMemo( () => !!checked || values.includes(value), [checked, values] ); const enabled = useMemo( () => !disabled && !groupDisabled, [disabled, groupDisabled] ); useEffect(() => { if (status == checked) { return; } if (onChange) { onChange(status); } }, [status, checked]); useEffect(() => { if (status == values.includes(value)) { return; } if (groupOnChange) { groupOnChange(status, value); } }, [status, values]); const toggleChecked = () => { if (!enabled) { return; } if (onChange) { onChange(!status); } if (groupOnChange) { groupOnChange(!status, value); } }; const el = () => { if (typeof children === "string") { return <>{children}; } if (typeof children === "function") { return children(status); } return children as React.ReactElement; }; return (
{customIndicator ? ( typeof customIndicator === "function" ? ( customIndicator(status) ) : ( customIndicator ) ) : ( )}
{el()}
); }; interface CheckboxGroupProps { values: T[]; onChange: (values: T[]) => void; children: JSX.Element | JSX.Element[]; disabled?: boolean; } export const CheckboxGroup = ({ values, onChange, children, disabled, }: CheckboxGroupProps) => { const handleChange = (checked: boolean, value: T) => { const index = values.findIndex((item) => item == value); let newValues: T[] = [...values]; // Add to list if (checked && index == -1) { newValues.push(value); } // Remove from list if (!checked && index > -1) { newValues.splice(index, 1); } onChange(newValues); }; return (
{children}
); };