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.

135 lines (131 loc) 4.98 kB
import { isReactText, isString } from "../utils/assertion.js"; import { filterUndefined } from "../utils/object.js"; import { cs } from "../utils/styles.js"; import fontSizes_default from "../theme/foundations/fontSizes.js"; import { useStyleConfig } from "../core/theme.js"; import styled from "../core/styled.js"; import vui from "../core/vui.js"; import { Icon } from "../icon/icon.js"; import { DismissButton } from "../dismissButton/DismissButton.js"; import { T } from "../t/t.js"; import { resolveTagVariantKey } from "./utils.js"; import { useEffect, useMemo } from "react"; import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime"; //#region src/tag/tag.tsx /** Outer container — rendered as <span> for static tags and <button> for interactive tags. */ const TagBase = styled.spanBox` /* Drives DismissButton color via cascade so the close affordance picks up the tag's text color. */ --vui-dismiss-fg: currentColor; align-items: center; display: inline-flex; font-weight: medium; justify-content: center; line-height: 1; max-width: 100%; position: relative; transition-duration: fast; width: fit-content; &:focus { outline: none; } `; /** * Displays text, icons or custom content. Can be made interactive or include a * dismiss affordance. When `isInteractive` (or `onClick` without `onDelete`) * is set, the tag renders as a `<button>` so it is keyboard-activatable. */ const Tag = vui((props, ref) => { const { children, className, deleteLabel = "Remove", icon, startIcon, endIcon, iconLeft, iconRight, color: colorProp, isInteractive = props.onClick !== void 0 && props.onDelete === void 0, isTruncated = true, itemLeft, itemRight, onClick, onDelete, size = "md", text, variant: variantProp, ...rest } = props; const resolvedVariant = useMemo(() => resolveTagVariantKey(variantProp, colorProp), [variantProp, colorProp]); useEffect(() => { if (iconLeft !== void 0) console.warn("[Tag] `iconLeft` is deprecated. Use `startIcon` instead."); if (iconRight !== void 0) console.warn("[Tag] `iconRight` is deprecated. Use `endIcon` instead."); if (variantProp !== void 0 && !["subtle", "solid"].includes(variantProp) && /^(subtle|solid)(Brand|Success|Danger|Warning|Lavender|Eucalyptus|Terracotta|Grey)$/.test(variantProp)) console.warn(`[Tag] Combined variant "${variantProp}" is deprecated. Use separate \`variant\` + \`color\` props instead (e.g. variant="subtle" color="blue").`); }, [ iconLeft, iconRight, variantProp ]); const resolvedStartIcon = startIcon ?? iconLeft; const resolvedEndIcon = endIcon ?? iconRight; const styles = useStyleConfig("Tag", { ...props, variant: resolvedVariant }); const { h, fontSize: themeFontSize, paddingX = 0, paddingY = 0, gapX = 0, borderRadius, bgHover, bgPressed, ...containerColors } = styles.container ?? {}; const dismissStyles = styles.dismiss ?? {}; const iconStyles = styles.icon ?? {}; const fontSize = `var(--vui-tag-font-size, ${fontSizes_default[themeFontSize] ?? themeFontSize}px)`; const iconSize = `var(--vui-tag-icon-size, ${iconStyles.fontSize || "1rem"})`; const TagIcon = ({ name, mr, ml }) => /* @__PURE__ */ jsx(Icon, { className: "vui-tagIcon", fontSize: iconSize, h: iconSize, ml, mr, w: iconSize, name }); const toPx = (v) => typeof v === "number" ? `${v}px` : v; const pxX = toPx(paddingX); const pxY = toPx(paddingY); const pxGap = toPx(gapX); const aliasedProps = filterUndefined({ borderRadius }); const interactiveStateProps = isInteractive ? filterUndefined({ hoverBg: bgHover, activeBg: bgPressed }) : void 0; const interactiveProps = isInteractive ? { as: "button", type: "button", cursor: "pointer", tabIndex: 0, userSelect: "none" } : {}; return /* @__PURE__ */ jsxs(TagBase, { className: cs("vui-tag", className), focusRing: 2, fontSize, h, isTruncated, onClick, px: pxX, py: pxY, ref, variant: resolvedVariant, ...containerColors, ...interactiveProps, ...interactiveStateProps, ...aliasedProps, ...rest, children: [isString(icon) ? /* @__PURE__ */ jsx(TagIcon, { name: icon }) : icon, !icon && /* @__PURE__ */ jsxs(Fragment$1, { children: [ itemLeft, isString(resolvedStartIcon) ? /* @__PURE__ */ jsx(TagIcon, { name: resolvedStartIcon, mr: pxGap }) : resolvedStartIcon, children ?? (isReactText(text) ? /* @__PURE__ */ jsx(T, { className: "vui-tagText", fontSize: "inherit", isTruncated, children: text }) : text), isString(resolvedEndIcon) ? /* @__PURE__ */ jsx(TagIcon, { name: resolvedEndIcon, ml: pxGap }) : resolvedEndIcon, onDelete && !isInteractive ? /* @__PURE__ */ jsx(DismissButton, { "aria-label": deleteLabel, className: "vui-tagButton", ml: pxGap, onClick: onDelete, ...dismissStyles }) : itemRight ] })] }); }); Tag.displayName = "Tag"; //#endregion export { Tag, Tag as default }; globalThis.__vuiVersion__ = "5.3.1" //# sourceMappingURL=tag.js.map