@hitachivantara/uikit-react-core
Version:
UI Kit Core React components.
160 lines (159 loc) • 6.47 kB
JavaScript
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 };