@hitachivantara/uikit-react-core
Version:
Core React components for the NEXT Design System.
164 lines (163 loc) • 5.59 kB
JavaScript
import { jsxs, jsx } from "react/jsx-runtime";
import { forwardRef, useCallback, useMemo, Children, cloneElement } from "react";
import { useDefaultProps } from "@hitachivantara/uikit-react-utils";
import { HvLabelContainer } from "../FormElement/LabelContainer.js";
import { useControlled } from "../hooks/useControlled.js";
import { useUniqueId } from "../hooks/useUniqueId.js";
import { setId } from "../utils/setId.js";
import { useClasses } from "./RadioGroup.styles.js";
import { staticClasses } from "./RadioGroup.styles.js";
import { HvFormElement } from "../FormElement/FormElement.js";
import { HvWarningText } from "../FormElement/WarningText/WarningText.js";
const getValueFromSelectedChildren = (children) => {
const childrenArray = Children.toArray(children);
const childrenCount = childrenArray.length;
for (let i = 0; i !== childrenCount; i += 1) {
const child = childrenArray[i];
const childIsControlled = child?.props?.checked !== void 0;
const childIsSelected = childIsControlled ? child?.props?.checked : child?.props?.defaultChecked;
if (childIsSelected) {
return child?.props?.value;
}
}
return null;
};
const HvRadioGroup = forwardRef(
function HvRadioGroup2(props, ref) {
const {
id,
classes: classesProp,
className,
children,
name,
value: valueProp,
defaultValue,
label,
description,
status,
statusMessage,
required,
readOnly,
disabled,
orientation = "vertical",
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
"aria-describedby": ariaDescribedBy,
"aria-errormessage": ariaErrorMessage,
onChange,
...others
} = useDefaultProps("HvRadioGroup", props);
const { classes, cx } = useClasses(classesProp);
const elementId = useUniqueId(id);
const [value, setValue] = useControlled(
valueProp,
defaultValue !== void 0 ? defaultValue : (
// When uncontrolled and no default value is given,
// extract the initial selected values from the children own state
() => getValueFromSelectedChildren(children)
)
);
const onChildChangeInterceptor = useCallback(
(childOnChange, event, isChecked, newValue) => {
childOnChange?.(event, isChecked, newValue);
onChange?.(event, newValue);
setValue(newValue);
},
[onChange, setValue]
);
const modifiedChildren = useMemo(() => {
return Children.map(children, (child) => {
const childValue = child?.props?.value ?? "on";
const childIsSelected = childValue === value;
return cloneElement(child, {
checked: childIsSelected,
name: child?.props?.name || name || elementId,
onChange: (event, isChecked, newValue) => onChildChangeInterceptor(
child?.props?.onChange,
event,
isChecked,
newValue
),
inputProps: {
...child?.props?.inputProps,
// Set the required attribute directly in the input
// the radio form element context shouldn't be aware so the
// label doesn't show redundant asterisk
required
},
disabled: disabled || child?.props?.disabled,
readOnly: readOnly || child?.props?.readOnly
});
});
}, [
children,
disabled,
elementId,
name,
onChildChangeInterceptor,
readOnly,
required,
value
]);
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: status || "standBy",
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__ */ jsx(
"div",
{
ref,
role: "radiogroup",
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy || label && setId(elementId, "label") || void 0,
"aria-invalid": status === "invalid" ? true : void 0,
"aria-errormessage": status === "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]: status === "invalid"
}),
...others,
children: modifiedChildren
}
),
canShowError && /* @__PURE__ */ jsx(
HvWarningText,
{
id: setId(elementId, "error"),
disableBorder: true,
className: classes.error,
children: statusMessage
}
)
]
}
);
}
);
export {
HvRadioGroup,
staticClasses as radioGroupClasses
};