braid-design-system
Version:
Themeable design system for the SEEK Group
215 lines (214 loc) • 6.67 kB
JavaScript
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
import { forwardRef, useRef, useEffect } from "react";
import { useBackgroundLightness } from "../../Box/BackgroundContext.mjs";
import { Box } from "../../Box/Box.mjs";
import { FieldOverlay } from "../FieldOverlay/FieldOverlay.mjs";
import { buildDataAttributes } from "../buildDataAttributes.mjs";
import { validateTabIndex } from "../validateTabIndex.mjs";
import { realField, sizeVars, isMixed, fakeField, selected, hideBorderOnDarkBackgroundInLightMode, hoverOverlay, checkboxIndicator, radioIndicator, disabledRadioIndicator } from "./InlineField.css.mjs";
import { IconMinus } from "../../icons/IconMinus/IconMinus.mjs";
import { IconTick } from "../../icons/IconTick/IconTick.mjs";
const tones = ["neutral", "critical"];
const Indicator = ({
type,
checked,
hover = false,
disabled = false
}) => {
const isCheckbox = type === "checkbox";
const iconTone = (() => {
if (disabled) {
return "secondary";
}
if (hover) {
return "formAccent";
}
})();
return isCheckbox ? /* @__PURE__ */ jsxs(
Box,
{
height: "full",
transition: "fast",
position: "relative",
className: checkboxIndicator,
children: [
/* @__PURE__ */ jsx(
Box,
{
position: "absolute",
inset: 0,
transition: "fast",
opacity: checked !== "mixed" ? 0 : void 0,
children: /* @__PURE__ */ jsx(IconMinus, { size: "fill", tone: iconTone })
}
),
/* @__PURE__ */ jsx(
Box,
{
position: "absolute",
inset: 0,
transition: "fast",
opacity: checked !== true ? 0 : void 0,
children: /* @__PURE__ */ jsx(IconTick, { size: "fill", tone: iconTone })
}
)
]
}
) : /* @__PURE__ */ jsx(
Box,
{
background: !disabled ? "formAccent" : void 0,
transition: "fast",
width: "full",
height: "full",
borderRadius: "full",
className: [
radioIndicator,
disabled ? disabledRadioIndicator : void 0
]
}
);
};
const StyledInput = forwardRef(
({
id,
name,
value,
checked,
data,
onChange,
type,
tone = "neutral",
disabled = false,
required,
tabIndex,
size = "standard",
"aria-describedby": ariaDescribedBy,
"aria-labelledby": ariaLabelledBy,
"aria-label": ariaLabel,
...restProps
}, forwardedRef) => {
const defaultRef = useRef(null);
const ref = forwardedRef || defaultRef;
if (tones.indexOf(tone) === -1) {
throw new Error(`Invalid tone: ${tone}`);
}
if (process.env.NODE_ENV !== "production") {
validateTabIndex(tabIndex);
}
const isCheckbox = type === "checkbox";
const fieldBorderRadius = isCheckbox ? "standard" : "full";
const accentBackground = disabled ? "neutralLight" : "formAccent";
const isMixed$1 = isCheckbox && checked === "mixed";
const fieldBackground = disabled ? { lightMode: "neutralSoft", darkMode: "neutral" } : { lightMode: "surface" };
const defaultBorder = checked ? "formAccent" : "default";
const indeterminateRef = useRef(isMixed$1);
const lastChecked = useRef(null);
indeterminateRef.current = isMixed$1;
if (isCheckbox && checked !== lastChecked.current && ref && typeof ref === "object" && ref.current) {
ref.current.indeterminate = indeterminateRef.current;
}
useEffect(() => {
if (isCheckbox && ref && typeof ref === "object" && ref.current) {
ref.current.indeterminate = indeterminateRef.current;
}
}, [ref, isCheckbox]);
useEffect(() => {
if (isCheckbox) {
lastChecked.current = checked;
}
}, [isCheckbox, checked]);
const { lightMode } = useBackgroundLightness();
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
Box,
{
component: "input",
type,
id,
name,
value,
onChange: (e) => {
if (isMixed$1) {
e.currentTarget.indeterminate = isMixed$1;
}
if (typeof onChange === "function") {
onChange(e);
}
},
checked: checked === "mixed" ? false : checked,
position: "absolute",
zIndex: 1,
className: [
realField,
sizeVars[size],
isMixed$1 ? isMixed : void 0
],
cursor: !disabled ? "pointer" : void 0,
opacity: 0,
"aria-describedby": ariaDescribedBy,
"aria-labelledby": ariaLabelledBy,
"aria-label": ariaLabel,
"aria-checked": isMixed$1 ? "mixed" : checked,
"aria-required": required,
disabled,
ref,
tabIndex,
...buildDataAttributes({ data, validateRestProps: restProps })
}
),
/* @__PURE__ */ jsxs(
Box,
{
flexShrink: 0,
position: "relative",
className: [fakeField, sizeVars[size]],
background: fieldBackground,
borderRadius: fieldBorderRadius,
children: [
/* @__PURE__ */ jsx(
FieldOverlay,
{
background: isCheckbox ? accentBackground : void 0,
borderRadius: fieldBorderRadius,
className: selected,
children: /* @__PURE__ */ jsx(Indicator, { type, disabled, checked })
}
),
/* @__PURE__ */ jsx(
FieldOverlay,
{
variant: disabled ? "disabled" : defaultBorder,
borderRadius: fieldBorderRadius,
visible: type === "radio" || !checked || disabled,
className: {
[hideBorderOnDarkBackgroundInLightMode]: lightMode === "dark"
}
}
),
/* @__PURE__ */ jsx(
FieldOverlay,
{
variant: "critical",
borderRadius: fieldBorderRadius,
visible: tone === "critical" && !disabled
}
),
/* @__PURE__ */ jsx(
FieldOverlay,
{
variant: "formAccent",
borderRadius: fieldBorderRadius,
className: hoverOverlay,
children: /* @__PURE__ */ jsx(Indicator, { type, hover: true, checked: true })
}
)
]
}
)
] });
}
);
export {
StyledInput
};