braid-design-system
Version:
Themeable design system for the SEEK Group
214 lines (212 loc) • 7.85 kB
JavaScript
import { jsxs, jsx } from "react/jsx-runtime";
import assert from "assert";
import clsx from "clsx";
import dedent from "dedent";
import { useId, Fragment } from "react";
import { textStyles } from "../../../css/typography.mjs";
import { useFallbackId } from "../../../hooks/useFallbackId.mjs";
import { useBackgroundLightness } from "../../Box/BackgroundContext.mjs";
import { Box } from "../../Box/Box.mjs";
import { FieldLabel } from "../../FieldLabel/FieldLabel.mjs";
import { FieldMessage } from "../../FieldMessage/FieldMessage.mjs";
import { Stack } from "../../Stack/Stack.mjs";
import { Text } from "../../Text/Text.mjs";
import { FieldOverlay } from "../FieldOverlay/FieldOverlay.mjs";
import { buildDataAttributes } from "../buildDataAttributes.mjs";
import { mergeIds } from "../mergeIds.mjs";
import { validateTabIndex } from "../validateTabIndex.mjs";
import { field, placeholderColor, iconSpace, secondaryIconSpace, verticalDivider, hideBorderOnDarkBackgroundInLightMode, hoverOverlay } from "./Field.css.mjs";
import { touchableText } from "../../../css/typography.css.mjs";
const Field = ({
id,
value,
name,
disabled,
autoComplete,
children,
description,
message,
secondaryMessage,
reserveMessageSpace = false,
tone,
"aria-describedby": ariaDescribedBy,
data,
secondaryIcon,
alwaysShowSecondaryIcon = false,
autoFocus,
icon,
prefix,
required,
tabIndex,
componentName,
...restProps
}) => {
assert(
prefix === void 0 || typeof prefix === "string",
"Prefix must be a string"
);
const resolvedId = useFallbackId(id);
const messageId = useId();
const descriptionId = useId();
if (process.env.NODE_ENV !== "production") {
if ("label" in restProps && typeof restProps.label === "string" && restProps.label.trim().length === 0 && !("aria-label" in restProps) && !("aria-labelledby" in restProps)) {
console.warn(
dedent`
The "label" prop is required as the accessible name for a ${componentName}.
If you are labelling the ${componentName} with another element or using a non-visual label please provide the appropriate props, either "aria-label" or "aria-labelledby".
See the ${componentName} documentation for more information: https://seek-oss.github.io/braid-design-system/components/${componentName}#indirect-or-hidden-field-labels
`
);
}
validateTabIndex(tabIndex);
}
const fieldBackground = disabled ? { lightMode: "neutralSoft", darkMode: "neutral" } : { lightMode: "surface" };
const hasValue = typeof value === "string" ? value.length > 0 : value != null;
const hasVisualLabelOrDescription = "label" in restProps && restProps.label || description;
const showSecondaryIcon = alwaysShowSecondaryIcon || secondaryIcon && hasValue;
const { lightMode } = useBackgroundLightness();
const overlays = /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
FieldOverlay,
{
variant: disabled ? "disabled" : "default",
visible: tone !== "critical" || disabled,
className: {
[hideBorderOnDarkBackgroundInLightMode]: lightMode === "dark"
}
}
),
/* @__PURE__ */ jsx(
FieldOverlay,
{
variant: "critical",
visible: tone === "critical" && !disabled
}
),
/* @__PURE__ */ jsx(FieldOverlay, { variant: "formAccent", className: hoverOverlay })
] });
const fieldPadding = "small";
return /* @__PURE__ */ jsxs(Stack, { space: "small", children: [
hasVisualLabelOrDescription ? /* @__PURE__ */ jsx(
FieldLabel,
{
htmlFor: resolvedId,
label: "label" in restProps ? restProps.label : void 0,
disabled,
secondaryLabel: "secondaryLabel" in restProps ? restProps.secondaryLabel : void 0,
tertiaryLabel: "tertiaryLabel" in restProps ? restProps.tertiaryLabel : void 0,
description,
descriptionId: description ? descriptionId : void 0
}
) : null,
/* @__PURE__ */ jsxs(Stack, { space: "xsmall", children: [
/* @__PURE__ */ jsx(
Box,
{
position: "relative",
background: fieldBackground,
borderRadius: "standard",
display: "flex",
children: children(
overlays,
{
id: resolvedId,
name,
background: fieldBackground,
width: "full",
paddingLeft: fieldPadding,
paddingRight: showSecondaryIcon ? void 0 : fieldPadding,
borderRadius: "standard",
"aria-describedby": mergeIds(
ariaDescribedBy,
message || secondaryMessage ? messageId : void 0,
description ? descriptionId : void 0
),
"aria-required": required,
..."aria-label" in restProps ? { "aria-label": restProps["aria-label"] } : {},
..."aria-labelledby" in restProps ? { "aria-labelledby": restProps["aria-labelledby"] } : {},
disabled,
autoComplete,
autoFocus,
tabIndex,
...buildDataAttributes({ data, validateRestProps: restProps }),
className: clsx(
field,
placeholderColor,
textStyles({
tone: hasValue && !disabled ? "neutral" : "secondary",
size: "standard",
baseline: false
}),
touchableText.standard,
icon && !prefix ? iconSpace : null,
showSecondaryIcon ? secondaryIconSpace : void 0
)
},
icon ? /* @__PURE__ */ jsx(
Box,
{
display: "flex",
alignItems: "center",
justifyContent: "center",
position: "absolute",
height: "touchable",
width: "touchable",
pointerEvents: "none",
top: 0,
left: 0,
children: /* @__PURE__ */ jsx(Text, { baseline: false, tone: prefix ? "secondary" : void 0, children: icon })
}
) : null,
secondaryIcon ? /* @__PURE__ */ jsx(
Box,
{
component: "span",
position: "absolute",
width: "touchable",
height: "touchable",
display: "flex",
alignItems: "center",
justifyContent: "center",
top: 0,
right: 0,
children: secondaryIcon
}
) : null,
prefix ? /* @__PURE__ */ jsxs(
Box,
{
component: "label",
htmlFor: resolvedId,
display: "flex",
alignItems: "center",
paddingLeft: icon ? void 0 : fieldPadding,
height: "touchable",
flexShrink: 0,
className: icon ? iconSpace : null,
children: [
/* @__PURE__ */ jsx(Text, { tone: "secondary", baseline: false, children: prefix }),
/* @__PURE__ */ jsx(Box, { padding: fieldPadding, paddingRight: "none", height: "full", children: /* @__PURE__ */ jsx(Box, { height: "full", className: verticalDivider }) })
]
}
) : null
)
}
),
(message || secondaryMessage) && !disabled || reserveMessageSpace ? /* @__PURE__ */ jsx(
FieldMessage,
{
id: messageId,
tone,
disabled,
message,
secondaryMessage,
reserveMessageSpace
}
) : null
] })
] });
};
export {
Field
};