@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
JavaScript
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