@heroui/radio
Version:
Radios allow users to select a single option from a list of mutually exclusive options.
481 lines (471 loc) • 17 kB
JavaScript
"use client";
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Radio: () => radio_default,
RadioGroup: () => radio_group_default,
RadioGroupProvider: () => RadioGroupProvider,
useRadio: () => useRadio,
useRadioGroup: () => useRadioGroup,
useRadioGroupContext: () => useRadioGroupContext
});
module.exports = __toCommonJS(index_exports);
// src/radio.tsx
var import_system2 = require("@heroui/system");
// src/use-radio.ts
var import_react = require("react");
var import_react2 = require("react");
var import_focus = require("@react-aria/focus");
var import_interactions = require("@react-aria/interactions");
var import_theme = require("@heroui/theme");
var import_radio = require("@react-aria/radio");
var import_system = require("@heroui/system");
var import_shared_utils = require("@heroui/shared-utils");
var import_react_utils2 = require("@heroui/react-utils");
// src/radio-group-context.ts
var import_react_utils = require("@heroui/react-utils");
var [RadioGroupProvider, useRadioGroupContext] = (0, import_react_utils.createContext)({
name: "RadioGroupContext",
strict: false
});
// src/use-radio.ts
function useRadio(props) {
var _a, _b, _c, _d, _e;
const globalContext = (0, import_system.useProviderContext)();
const groupContext = useRadioGroupContext();
const {
as,
ref,
classNames,
id,
value,
children,
description,
size = (_a = groupContext == null ? void 0 : groupContext.size) != null ? _a : "md",
color = (_b = groupContext == null ? void 0 : groupContext.color) != null ? _b : "primary",
isDisabled: isDisabledProp = (_c = groupContext == null ? void 0 : groupContext.isDisabled) != null ? _c : false,
disableAnimation = (_e = (_d = groupContext == null ? void 0 : groupContext.disableAnimation) != null ? _d : globalContext == null ? void 0 : globalContext.disableAnimation) != null ? _e : false,
onChange = groupContext == null ? void 0 : groupContext.onChange,
autoFocus = false,
className,
...otherProps
} = props;
if (groupContext && import_shared_utils.__DEV__) {
if ("checked" in otherProps) {
(0, import_shared_utils.warn)('Remove props "checked" if in the Radio.Group.', "Radio");
}
if (value === void 0) {
(0, import_shared_utils.warn)('Props "value" must be defined if in the Radio.Group.', "Radio");
}
}
const Component = as || "label";
const domRef = (0, import_react_utils2.useDOMRef)(ref);
const inputRef = (0, import_react2.useRef)(null);
const labelId = (0, import_react.useId)();
const descriptionId = (0, import_react.useId)();
const isRequired = (0, import_react2.useMemo)(() => {
var _a2;
return (_a2 = groupContext.isRequired) != null ? _a2 : false;
}, [groupContext.isRequired]);
const isInvalid = groupContext.isInvalid;
const ariaRadioProps = (0, import_react2.useMemo)(() => {
const ariaDescribedBy = [otherProps["aria-describedby"], descriptionId].filter(Boolean).join(" ") || void 0;
return {
id,
isRequired,
isDisabled: isDisabledProp,
"aria-label": otherProps["aria-label"],
"aria-labelledby": otherProps["aria-labelledby"] || labelId,
"aria-describedby": ariaDescribedBy
};
}, [
id,
isDisabledProp,
isRequired,
description,
otherProps["aria-label"],
otherProps["aria-labelledby"],
otherProps["aria-describedby"],
descriptionId
]);
const { inputProps, isDisabled, isSelected, isPressed } = (0, import_radio.useRadio)(
{
value,
children: typeof children === "function" ? true : children,
...ariaRadioProps
},
groupContext.groupState,
inputRef
);
const { focusProps, isFocused, isFocusVisible } = (0, import_focus.useFocusRing)({
autoFocus
});
const interactionDisabled = isDisabled || inputProps.readOnly;
const { hoverProps, isHovered } = (0, import_interactions.useHover)({
isDisabled: interactionDisabled
});
const pressed = interactionDisabled ? false : isPressed;
const slots = (0, import_react2.useMemo)(
() => (0, import_theme.radio)({
color,
size,
isInvalid,
isDisabled,
disableAnimation
}),
[color, size, isDisabled, isInvalid, disableAnimation]
);
const baseStyles = (0, import_shared_utils.clsx)(classNames == null ? void 0 : classNames.base, className);
const getBaseProps = (0, import_react.useCallback)(
(props2 = {}) => {
return {
...props2,
ref: domRef,
className: slots.base({ class: baseStyles }),
"data-disabled": (0, import_shared_utils.dataAttr)(isDisabled),
"data-focus": (0, import_shared_utils.dataAttr)(isFocused),
"data-focus-visible": (0, import_shared_utils.dataAttr)(isFocusVisible),
"data-selected": (0, import_shared_utils.dataAttr)(isSelected),
"data-invalid": (0, import_shared_utils.dataAttr)(isInvalid),
"data-hover": (0, import_shared_utils.dataAttr)(isHovered),
"data-pressed": (0, import_shared_utils.dataAttr)(pressed),
"data-hover-unselected": (0, import_shared_utils.dataAttr)(isHovered && !isSelected),
"data-readonly": (0, import_shared_utils.dataAttr)(inputProps.readOnly),
"aria-required": (0, import_shared_utils.dataAttr)(isRequired),
...(0, import_shared_utils.mergeProps)(hoverProps, otherProps)
};
},
[
slots,
baseStyles,
domRef,
isDisabled,
isFocused,
isFocusVisible,
isSelected,
isInvalid,
isHovered,
pressed,
inputProps.readOnly,
isRequired,
otherProps
]
);
const getWrapperProps = (0, import_react.useCallback)(
(props2 = {}) => {
return {
...props2,
"aria-hidden": true,
className: (0, import_shared_utils.clsx)(slots.wrapper({ class: (0, import_shared_utils.clsx)(classNames == null ? void 0 : classNames.wrapper, props2.className) }))
};
},
[slots, classNames == null ? void 0 : classNames.wrapper]
);
const getInputProps = (0, import_react.useCallback)(
(props2 = {}) => {
return {
ref: inputRef,
...(0, import_shared_utils.mergeProps)(props2, inputProps, focusProps),
className: slots.hiddenInput({ class: classNames == null ? void 0 : classNames.hiddenInput }),
onChange: (0, import_shared_utils.chain)(inputProps.onChange, onChange)
};
},
[inputProps, focusProps, onChange]
);
const getLabelProps = (0, import_react.useCallback)(
(props2 = {}) => ({
...props2,
id: labelId,
className: slots.label({ class: classNames == null ? void 0 : classNames.label })
}),
[slots, classNames == null ? void 0 : classNames.label, isDisabled, isSelected, isInvalid]
);
const getLabelWrapperProps = (0, import_react.useCallback)(
(props2 = {}) => ({
...props2,
className: slots.labelWrapper({ class: classNames == null ? void 0 : classNames.labelWrapper })
}),
[slots, classNames == null ? void 0 : classNames.labelWrapper]
);
const getControlProps = (0, import_react.useCallback)(
(props2 = {}) => ({
...props2,
className: slots.control({ class: classNames == null ? void 0 : classNames.control })
}),
[slots, classNames == null ? void 0 : classNames.control]
);
const getDescriptionProps = (0, import_react.useCallback)(
(props2 = {}) => ({
...props2,
id: descriptionId,
className: slots.description({ class: classNames == null ? void 0 : classNames.description })
}),
[slots, classNames == null ? void 0 : classNames.description]
);
return {
Component,
children,
isSelected,
isDisabled,
isInvalid,
isFocusVisible,
description,
getBaseProps,
getWrapperProps,
getInputProps,
getLabelProps,
getLabelWrapperProps,
getControlProps,
getDescriptionProps
};
}
// src/radio.tsx
var import_jsx_runtime = require("react/jsx-runtime");
var Radio = (0, import_system2.forwardRef)((props, ref) => {
const {
Component,
children,
description,
getBaseProps,
getWrapperProps,
getInputProps,
getLabelProps,
getLabelWrapperProps,
getControlProps,
getDescriptionProps
} = useRadio({ ...props, ref });
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Component, { ...getBaseProps(), children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ...getInputProps() }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...getWrapperProps(), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...getControlProps() }) }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ...getLabelWrapperProps(), children: [
children && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...getLabelProps(), children }),
description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...getDescriptionProps(), children: description })
] })
] });
});
Radio.displayName = "HeroUI.Radio";
var radio_default = Radio;
// src/radio-group.tsx
var import_system4 = require("@heroui/system");
// src/use-radio-group.ts
var import_theme2 = require("@heroui/theme");
var import_react3 = require("react");
var import_radio2 = require("@react-stately/radio");
var import_radio3 = require("@react-aria/radio");
var import_system3 = require("@heroui/system");
var import_react_utils3 = require("@heroui/react-utils");
var import_shared_utils2 = require("@heroui/shared-utils");
var import_form = require("@heroui/form");
function useRadioGroup(props) {
var _a, _b;
const globalContext = (0, import_system3.useProviderContext)();
const { validationBehavior: formValidationBehavior } = (0, import_form.useSlottedContext)(import_form.FormContext) || {};
const {
as,
ref,
classNames,
children,
label,
value,
name,
isInvalid: isInvalidProp,
validationState,
validationBehavior = (_a = formValidationBehavior != null ? formValidationBehavior : globalContext == null ? void 0 : globalContext.validationBehavior) != null ? _a : "native",
size = "md",
color = "primary",
isDisabled = false,
disableAnimation = (_b = globalContext == null ? void 0 : globalContext.disableAnimation) != null ? _b : false,
orientation = "vertical",
isRequired = false,
isReadOnly,
errorMessage,
description,
className,
onChange,
onValueChange,
...otherProps
} = props;
const Component = as || "div";
const shouldFilterDOMProps = typeof Component === "string";
const domRef = (0, import_react_utils3.useDOMRef)(ref);
const otherPropsWithOrientation = (0, import_react3.useMemo)(() => {
return {
...otherProps,
value,
name,
"aria-label": (0, import_shared_utils2.safeAriaLabel)(otherProps["aria-label"], label),
isRequired,
isReadOnly,
isInvalid: validationState === "invalid" || isInvalidProp,
orientation,
validationBehavior,
onChange: onValueChange
};
}, [
otherProps,
value,
name,
label,
isRequired,
isReadOnly,
isInvalidProp,
validationState,
validationBehavior,
orientation,
onValueChange
]);
const groupState = (0, import_radio2.useRadioGroupState)(otherPropsWithOrientation);
const {
labelProps,
radioGroupProps: groupProps,
errorMessageProps,
descriptionProps,
isInvalid: isAriaInvalid,
validationErrors,
validationDetails
} = (0, import_radio3.useRadioGroup)(otherPropsWithOrientation, groupState);
const isInvalid = otherPropsWithOrientation.isInvalid || isAriaInvalid || groupState.isInvalid;
const context = (0, import_react3.useMemo)(
() => ({
size,
color,
groupState,
isRequired,
isInvalid,
isDisabled,
disableAnimation,
onChange
}),
[
size,
color,
isRequired,
isDisabled,
isInvalid,
onChange,
disableAnimation,
groupState.name,
groupState.isDisabled,
groupState.isReadOnly,
groupState.isRequired,
groupState.selectedValue,
groupState.lastFocusedValue
]
);
const slots = (0, import_react3.useMemo)(
() => (0, import_theme2.radioGroup)({ isRequired, isInvalid, disableAnimation }),
[isInvalid, isRequired, disableAnimation]
);
const baseStyles = (0, import_shared_utils2.clsx)(classNames == null ? void 0 : classNames.base, className);
const getGroupProps = (0, import_react3.useCallback)(() => {
return {
ref: domRef,
className: slots.base({ class: baseStyles }),
...(0, import_shared_utils2.mergeProps)(
groupProps,
(0, import_react_utils3.filterDOMProps)(otherProps, {
enabled: shouldFilterDOMProps
})
)
};
}, [domRef, slots, baseStyles, groupProps, otherProps]);
const getLabelProps = (0, import_react3.useCallback)(() => {
return {
className: slots.label({ class: classNames == null ? void 0 : classNames.label }),
...labelProps
};
}, [slots, classNames == null ? void 0 : classNames.label, labelProps, classNames == null ? void 0 : classNames.label]);
const getWrapperProps = (0, import_react3.useCallback)(() => {
return {
className: slots.wrapper({ class: classNames == null ? void 0 : classNames.wrapper }),
role: "presentation",
"data-orientation": orientation
};
}, [slots, classNames == null ? void 0 : classNames.wrapper, orientation, slots.wrapper]);
const getDescriptionProps = (0, import_react3.useCallback)(
(props2 = {}) => {
return {
...props2,
...descriptionProps,
className: slots.description({ class: (0, import_shared_utils2.clsx)(classNames == null ? void 0 : classNames.description, props2 == null ? void 0 : props2.className) })
};
},
[slots, classNames == null ? void 0 : classNames.description, descriptionProps, slots.description]
);
const getErrorMessageProps = (0, import_react3.useCallback)(
(props2 = {}) => {
return {
...props2,
...errorMessageProps,
className: slots.errorMessage({ class: (0, import_shared_utils2.clsx)(classNames == null ? void 0 : classNames.errorMessage, props2 == null ? void 0 : props2.className) })
};
},
[slots, classNames == null ? void 0 : classNames.errorMessage, errorMessageProps]
);
return {
Component,
children,
label,
context,
description,
isInvalid,
errorMessage: typeof errorMessage === "function" ? errorMessage({ isInvalid, validationErrors, validationDetails }) : errorMessage || (validationErrors == null ? void 0 : validationErrors.join(" ")),
getGroupProps,
getLabelProps,
getWrapperProps,
getDescriptionProps,
getErrorMessageProps
};
}
// src/radio-group.tsx
var import_jsx_runtime2 = require("react/jsx-runtime");
var RadioGroup = (0, import_system4.forwardRef)((props, ref) => {
const {
Component,
children,
label,
context,
description,
isInvalid,
errorMessage,
getGroupProps,
getLabelProps,
getWrapperProps,
getDescriptionProps,
getErrorMessageProps
} = useRadioGroup({ ...props, ref });
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Component, { ...getGroupProps(), children: [
label && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { ...getLabelProps(), children: label }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ...getWrapperProps(), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RadioGroupProvider, { value: context, children }) }),
isInvalid && errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ...getErrorMessageProps(), children: errorMessage }) : description ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ...getDescriptionProps(), children: description }) : null
] });
});
RadioGroup.displayName = "HeroUI.RadioGroup";
var radio_group_default = RadioGroup;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Radio,
RadioGroup,
RadioGroupProvider,
useRadio,
useRadioGroup,
useRadioGroupContext
});