UNPKG

@veracity/vui

Version:

Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.

182 lines (174 loc) 5.91 kB
import { filterUndefined } from "../utils/object.js"; import { cs } from "../utils/styles.js"; import { selectionControlColors, selectionControlDisabled } from "../selectionControl/consts.js"; import { omitThemingProps, th, useStyleConfig } from "../core/theme.js"; import styled from "../core/styled.js"; import vui from "../core/vui.js"; import { Box } from "../box/box.js"; import { T } from "../t/t.js"; import { SelectionControlInput, useDeprecatedLgSize, useSelectionControlColors, useSelectionControlDescription } from "../selectionControl/selectionControl.js"; import { useRadioGroupContext } from "./context.js"; import { useEffect, useState } from "react"; import { jsx, jsxs } from "react/jsx-runtime"; //#region src/radio/radio.tsx const dotSize = { lg: "12px", md: "12px", sm: "10px", xs: "8px" }; const jsxChildrenMt = { lg: "0px", md: "0px", sm: "2px", xs: "3px" }; const labelMt = { lg: "0px", md: "0px", sm: "0.5px", xs: "1px" }; const RadioControl = styled.spanBox` align-items: center; border: 1px solid currentColor; border-radius: 50%; display: inline-flex; flex-shrink: 0; justify-content: center; position: relative; transition-duration: fast; `; const RadioDot = styled.spanBox` background-color: currentColor; border-radius: 50%; flex-shrink: 0; `; const RadioBase = styled.labelBox` cursor: pointer; display: inline-flex; width: fit-content; &:not([aria-disabled='true']):not([aria-readonly='true']):hover .vui-radioControl { color: ${(p) => th.color(p.controlHoverColor)}; } &:not([aria-disabled='true']):not([aria-readonly='true']):active .vui-radioControl { color: ${(p) => th.color(p.controlPressedColor)}; } &[aria-readonly='true'] { cursor: auto; } &:not([aria-disabled='true']):not([aria-readonly='true']) .vui-radioControl:focus-within { color: ${selectionControlColors.focus}; } &[aria-disabled='true'] { color: ${selectionControlDisabled.text}; cursor: not-allowed; .vui-radioControl { color: ${selectionControlDisabled.icon}; } } `; /** * Allows selection of a single choice from a set of items. Handles controlled and uncontrolled modes. * The ring and the inner dot shown when checked are both plain CSS — no icon assets involved. */ const Radio = vui((props, ref) => { const { defaultValue: groupDefaultValue, isChecked: groupIsChecked, onChange: groupOnChange, value: groupValue, ...radioGroupProps } = useRadioGroupContext() ?? {}; const defaultIsChecked = groupIsChecked !== void 0 ? groupIsChecked === props.value : void 0; const mergedProps = { ...radioGroupProps, ...props }; const { checked = groupValue !== void 0 ? props.value === groupValue : void 0, children, className, defaultChecked = groupDefaultValue !== void 0 ? props.value === groupDefaultValue : void 0, disabled, errorText, readOnly, helpText, id: idProp, inputProps, inputRef, label, name, onChange, required, value, ...rest } = omitThemingProps(mergedProps); const [isChecked, setIsChecked] = useState(defaultIsChecked ?? checked ?? defaultChecked); const styles = useStyleConfig("Radio", mergedProps); const { color: controlColor, hoverColor, pressedColor, ...controlStyles } = styles.control; const size = mergedProps.size ?? "md"; const { description, descriptionId, errorText: effectiveErrorText, id } = useSelectionControlDescription(idProp, helpText, errorText, !!isChecked); const hasJsxChildren = !!children; const controlMr = children || label ? 1 : 0; const { color, controlHoverColor, controlPressedColor, descriptionColor, labelColor } = useSelectionControlColors({ controlColor, disabled, errorText: effectiveErrorText, hoverColor, isActive: !!isChecked, pressedColor, readOnly }); useDeprecatedLgSize(size, "Radio"); useEffect(() => { if (groupIsChecked !== void 0) setIsChecked(groupIsChecked === value); else if (checked !== void 0) setIsChecked(checked); }, [checked, groupIsChecked]); function handleOnChange(e) { if (readOnly) return; if (checked === void 0 && groupIsChecked === void 0) setIsChecked(e.target.checked); groupOnChange?.(e); onChange?.(e); } const aliasedProps = filterUndefined({ "aria-disabled": disabled, "aria-readonly": readOnly }); return /* @__PURE__ */ jsxs(RadioBase, { alignItems: label || hasJsxChildren ? "flex-start" : "center", className: cs("vui-radio", className), controlHoverColor, controlPressedColor, ref, ...styles.container, ...aliasedProps, ...rest, children: [/* @__PURE__ */ jsxs(RadioControl, { bg: "white", className: "vui-radioControl", color, focusWithinRing: 3, mr: controlMr, mt: hasJsxChildren ? jsxChildrenMt[size] ?? jsxChildrenMt.md : label ? labelMt[size] ?? labelMt.md : void 0, ...controlStyles, children: [/* @__PURE__ */ jsx(SelectionControlInput, { "aria-describedby": descriptionId, "aria-invalid": !!effectiveErrorText || void 0, className: "vui-radioInput", onChange: handleOnChange, ref: inputRef, type: "radio", checked, defaultChecked, disabled, id, name, required, value, ...inputProps }), isChecked && /* @__PURE__ */ jsx(RadioDot, { className: "vui-radioDot", h: dotSize[size] ?? dotSize.md, w: dotSize[size] ?? dotSize.md })] }), children ?? (label && /* @__PURE__ */ jsxs(Box, { column: true, children: [/* @__PURE__ */ jsx(T, { className: "vui-radioLabel", color: labelColor, variant: "caption", ...styles.label, children: label }), description && /* @__PURE__ */ jsx(T, { className: "vui-radioDescription", color: descriptionColor, id: descriptionId, mt: "2px", size: "sm", children: description })] }))] }); }); Radio.displayName = "Radio"; //#endregion export { Radio, Radio as default, RadioBase }; globalThis.__vuiVersion__ = "5.4.0" //# sourceMappingURL=radio.js.map