UNPKG

braid-design-system

Version:
214 lines (212 loc) • 7.85 kB
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 };