UNPKG

@hitachivantara/uikit-react-core

Version:
160 lines (159 loc) 6.47 kB
import { setId } from "../utils/setId.js"; import { useUniqueId } from "../hooks/useUniqueId.js"; import { HvFormElement } from "../FormElement/FormElement.js"; import { HvWarningText } from "../FormElement/WarningText/WarningText.js"; import { useControlled } from "../hooks/useControlled.js"; import { HvLabelContainer } from "../FormElement/LabelContainer.js"; import { multiSelectionEventHandler } from "../utils/multiSelectionEventHandler.js"; import { HvCheckBox } from "../CheckBox/CheckBox.js"; import { CounterLabel } from "../utils/CounterLabel.js"; import { useClasses } from "./CheckBoxGroup.styles.js"; import { useDefaultProps } from "@hitachivantara/uikit-react-utils"; import { Children, cloneElement, forwardRef, useCallback, useMemo, useRef } from "react"; import { jsx, jsxs } from "react/jsx-runtime"; //#region src/CheckBoxGroup/CheckBoxGroup.tsx var computeSelectAllState = (selected, total) => { if (selected === 0) return "none"; if (selected === total) return "all"; return "some"; }; var getValueFromSelectedChildren = (children) => { return Children.toArray(children).map((child) => { return (child?.props?.checked !== void 0 ? child?.props?.checked : child?.props?.defaultChecked) ? child?.props?.value : void 0; }).filter((v) => v !== void 0); }; /** * A checkbox group is a type of selection list that allows the user to select multiple options through the use of checkboxes. */ var HvCheckBoxGroup = forwardRef(function HvCheckBoxGroup(props, ref) { const { id, classes: classesProp, className, children, name, label, description, status, statusMessage, defaultValue, value: valueProp, required, readOnly, disabled, showSelectAll, orientation = "vertical", selectAllConjunctionLabel = "/", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-errormessage": ariaErrorMessage, onChange, ...others } = useDefaultProps("HvCheckBoxGroup", props); const { classes, cx } = useClasses(classesProp); const [value, setValue] = useControlled(valueProp, defaultValue !== void 0 ? defaultValue : () => getValueFromSelectedChildren(children)); const [validationState, setValidationState] = useControlled(status, "standBy"); const [validationMessage] = useControlled(statusMessage, "Required"); const elementId = useUniqueId(id); const selectionAnchor = useRef(void 0); const [allValues, selectedState, selectedCount] = useMemo(() => { const childValues = []; const childSelectedState = []; let childSelectedCounter = 0; Children.toArray(children).forEach((child, i) => { const childValue = child?.props?.value; const childIsSelected = value.indexOf(childValue) !== -1; childValues[i] = childValue; childSelectedState[i] = childIsSelected; if (childIsSelected) childSelectedCounter += 1; }); return [ childValues, childSelectedState, childSelectedCounter ]; }, [children, value]); const selectAllState = computeSelectAllState(value.length, selectedState.length); const onChildChangeInterceptor = useCallback((index, childOnChange, event, isChecked) => { const newValue = multiSelectionEventHandler(event, index, selectionAnchor, allValues, selectedState, isChecked); childOnChange?.(event, isChecked); onChange?.(event, newValue); setValue(() => { if (required && newValue.length === 0) setValidationState("invalid"); else setValidationState("valid"); return newValue; }); }, [ allValues, onChange, required, selectedState, setValidationState, setValue ]); const modifiedChildren = useMemo(() => { return Children.map(children, (child, i) => { const childIsSelected = selectedState[i]; return cloneElement(child, { checked: childIsSelected, name: child?.props?.name || name, onChange: (event, isChecked) => onChildChangeInterceptor(i, child?.props?.onChange, event, isChecked), disabled: disabled || child?.props?.disabled, readOnly: readOnly || child?.props?.readOnly }); }); }, [ children, disabled, name, onChildChangeInterceptor, readOnly, selectedState ]); const handleSelectAll = (event, selectAllChecked) => { let newValue; if (selectAllState === "some") newValue = []; else if (selectAllChecked) newValue = [...allValues]; else newValue = []; onChange?.(event, newValue); setValue(() => { if (required && newValue.length === 0) setValidationState("invalid"); else setValidationState("valid"); return newValue; }); }; const canShowError = ariaErrorMessage == null && (status !== void 0 && statusMessage !== void 0 || status === void 0 && required); const errorMessageId = canShowError ? setId(elementId, "error") : ariaErrorMessage; return /* @__PURE__ */ jsxs(HvFormElement, { id, name, status: validationState, disabled, required, readOnly, className: cx(classes.root, className), children: [ /* @__PURE__ */ jsx(HvLabelContainer, { label, description, labelId: setId(elementId, "label"), descriptionId: setId(elementId, "description"), classes: { label: classes.label } }), /* @__PURE__ */ jsxs("div", { ref, role: "group", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy || label && setId(elementId, "label") || void 0, "aria-disabled": disabled ? true : void 0, "aria-invalid": validationState === "invalid" ? true : void 0, "aria-errormessage": validationState === "invalid" ? errorMessageId : void 0, "aria-describedby": [description && setId(elementId, "description"), ariaDescribedBy].join(" ").trim() || void 0, className: cx(classes.group, { [classes.vertical]: orientation === "vertical", [classes.horizontal]: orientation === "horizontal", [classes.invalid]: validationState === "invalid" }), ...others, children: [showSelectAll && /* @__PURE__ */ jsx(HvCheckBox, { checked: selectAllState === "all", indeterminate: selectAllState === "some", label: /* @__PURE__ */ jsx(CounterLabel, { selected: selectedCount, total: Children.count(children), conjunctionLabel: selectAllConjunctionLabel }), disabled, readOnly, className: classes.selectAll, onChange: handleSelectAll }), modifiedChildren] }), canShowError && /* @__PURE__ */ jsx(HvWarningText, { id: setId(elementId, "error"), disableBorder: true, className: classes.error, children: validationMessage }) ] }); }); //#endregion export { HvCheckBoxGroup };