@fanvue/ui 3.8.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Alert/Alert.cjs +28 -5
- package/dist/cjs/components/Alert/Alert.cjs.map +1 -1
- package/dist/cjs/components/Badge/Badge.cjs +17 -5
- package/dist/cjs/components/Badge/Badge.cjs.map +1 -1
- package/dist/cjs/components/Checkbox/Checkbox.cjs +1 -1
- package/dist/cjs/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/cjs/components/Dialog/Dialog.cjs +21 -8
- package/dist/cjs/components/Dialog/Dialog.cjs.map +1 -1
- package/dist/cjs/components/FanFollowerCount/FanFollowerCount.cjs +64 -0
- package/dist/cjs/components/FanFollowerCount/FanFollowerCount.cjs.map +1 -0
- package/dist/cjs/components/IconButton/IconButton.cjs +1 -1
- package/dist/cjs/components/IconButton/IconButton.cjs.map +1 -1
- package/dist/cjs/components/Link/Link.cjs +85 -0
- package/dist/cjs/components/Link/Link.cjs.map +1 -0
- package/dist/cjs/components/Pill/Pill.cjs +3 -1
- package/dist/cjs/components/Pill/Pill.cjs.map +1 -1
- package/dist/cjs/components/ProfileStatus/ProfileStatus.cjs +51 -0
- package/dist/cjs/components/ProfileStatus/ProfileStatus.cjs.map +1 -0
- package/dist/cjs/components/Radio/Radio.cjs +65 -34
- package/dist/cjs/components/Radio/Radio.cjs.map +1 -1
- package/dist/cjs/components/Select/Select.cjs +4 -4
- package/dist/cjs/components/Select/Select.cjs.map +1 -1
- package/dist/cjs/components/TextField/TextField.cjs +4 -4
- package/dist/cjs/components/TextField/TextField.cjs.map +1 -1
- package/dist/cjs/index.cjs +6 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/components/Alert/Alert.mjs +28 -5
- package/dist/components/Alert/Alert.mjs.map +1 -1
- package/dist/components/Badge/Badge.mjs +17 -5
- package/dist/components/Badge/Badge.mjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.mjs +1 -1
- package/dist/components/Checkbox/Checkbox.mjs.map +1 -1
- package/dist/components/Dialog/Dialog.mjs +21 -8
- package/dist/components/Dialog/Dialog.mjs.map +1 -1
- package/dist/components/FanFollowerCount/FanFollowerCount.mjs +47 -0
- package/dist/components/FanFollowerCount/FanFollowerCount.mjs.map +1 -0
- package/dist/components/IconButton/IconButton.mjs +1 -1
- package/dist/components/IconButton/IconButton.mjs.map +1 -1
- package/dist/components/Link/Link.mjs +68 -0
- package/dist/components/Link/Link.mjs.map +1 -0
- package/dist/components/Pill/Pill.mjs +3 -1
- package/dist/components/Pill/Pill.mjs.map +1 -1
- package/dist/components/ProfileStatus/ProfileStatus.mjs +34 -0
- package/dist/components/ProfileStatus/ProfileStatus.mjs.map +1 -0
- package/dist/components/Radio/Radio.mjs +66 -35
- package/dist/components/Radio/Radio.mjs.map +1 -1
- package/dist/components/Select/Select.mjs +4 -4
- package/dist/components/Select/Select.mjs.map +1 -1
- package/dist/components/TextField/TextField.mjs +4 -4
- package/dist/components/TextField/TextField.mjs.map +1 -1
- package/dist/index.d.ts +158 -11
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
4
|
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const reactSlot = require("@radix-ui/react-slot");
|
|
5
6
|
const React = require("react");
|
|
6
7
|
const cn = require("../../utils/cn.cjs");
|
|
7
8
|
const Button = require("../Button/Button.cjs");
|
|
@@ -31,13 +32,22 @@ const DEFAULT_ICONS = {
|
|
|
31
32
|
info: /* @__PURE__ */ jsxRuntime.jsx(InfoCircleIcon.InfoCircleIcon, {}),
|
|
32
33
|
success: /* @__PURE__ */ jsxRuntime.jsx(CheckCircleIcon.CheckCircleIcon, {}),
|
|
33
34
|
warning: /* @__PURE__ */ jsxRuntime.jsx(WarningTriangleIcon.WarningTriangleIcon, {}),
|
|
34
|
-
error: /* @__PURE__ */ jsxRuntime.jsx(ErrorCircleIcon.ErrorCircleIcon, {})
|
|
35
|
+
error: /* @__PURE__ */ jsxRuntime.jsx(ErrorCircleIcon.ErrorCircleIcon, {}),
|
|
36
|
+
neutral: /* @__PURE__ */ jsxRuntime.jsx(InfoCircleIcon.InfoCircleIcon, {})
|
|
35
37
|
};
|
|
36
38
|
const CLOSE_BUTTON_CLASSES = {
|
|
37
39
|
info: "hover:bg-info-content/10 active:bg-info-content/20 text-info-content motion-safe:transition-colors motion-safe:duration-150",
|
|
38
40
|
success: "hover:bg-success-content/10 active:bg-success-content/20 text-success-content motion-safe:transition-colors motion-safe:duration-150",
|
|
39
41
|
warning: "hover:bg-warning-content/10 active:bg-warning-content/20 text-warning-content motion-safe:transition-colors motion-safe:duration-150",
|
|
40
|
-
error: "hover:bg-error-content/10 active:bg-error-content/20 text-error-content motion-safe:transition-colors motion-safe:duration-150"
|
|
42
|
+
error: "hover:bg-error-content/10 active:bg-error-content/20 text-error-content motion-safe:transition-colors motion-safe:duration-150",
|
|
43
|
+
neutral: "hover:bg-content-secondary/10 active:bg-content-secondary/20 text-content-secondary motion-safe:transition-colors motion-safe:duration-150"
|
|
44
|
+
};
|
|
45
|
+
const LINK_CLASSES = {
|
|
46
|
+
info: "text-alerts-info-prompt-content-info",
|
|
47
|
+
success: "text-alerts-info-prompt-content-success",
|
|
48
|
+
warning: "text-alerts-info-prompt-content-warning",
|
|
49
|
+
error: "text-alerts-info-prompt-content-error",
|
|
50
|
+
neutral: "text-content-secondary"
|
|
41
51
|
};
|
|
42
52
|
const Alert = React__namespace.forwardRef(
|
|
43
53
|
({
|
|
@@ -48,6 +58,7 @@ const Alert = React__namespace.forwardRef(
|
|
|
48
58
|
closable = false,
|
|
49
59
|
onClose,
|
|
50
60
|
closeLabel = "Close alert",
|
|
61
|
+
action,
|
|
51
62
|
children,
|
|
52
63
|
...props
|
|
53
64
|
}, ref) => {
|
|
@@ -56,7 +67,6 @@ const Alert = React__namespace.forwardRef(
|
|
|
56
67
|
"div",
|
|
57
68
|
{
|
|
58
69
|
ref,
|
|
59
|
-
role: "alert",
|
|
60
70
|
"data-testid": "alert",
|
|
61
71
|
className: cn.cn(
|
|
62
72
|
"grid gap-x-3 rounded-xs p-4 text-sm leading-[18px]",
|
|
@@ -69,14 +79,27 @@ const Alert = React__namespace.forwardRef(
|
|
|
69
79
|
variant === "success" && "bg-success-surface text-success-content",
|
|
70
80
|
variant === "warning" && "bg-warning-surface text-warning-content",
|
|
71
81
|
variant === "error" && "bg-error-surface text-error-content",
|
|
82
|
+
variant === "neutral" && "bg-alerts-info-prompt-background-neutral text-alerts-info-prompt-icon-neutral",
|
|
72
83
|
className
|
|
73
84
|
),
|
|
74
85
|
...props,
|
|
75
86
|
children: [
|
|
76
87
|
resolvedIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-start h-full", "aria-hidden": "true", children: resolvedIcon }),
|
|
77
88
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [
|
|
78
|
-
|
|
79
|
-
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: "flex flex-col gap-2", children: [
|
|
90
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "typography-body-small-14px-semibold text-content-primary", children: title }),
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "typography-body-small-14px-regular text-content-primary", children })
|
|
92
|
+
] }),
|
|
93
|
+
action && /* @__PURE__ */ jsxRuntime.jsx(
|
|
94
|
+
reactSlot.Slot,
|
|
95
|
+
{
|
|
96
|
+
className: cn.cn(
|
|
97
|
+
"typography-body-small-14px-semibold w-fit cursor-pointer underline underline-offset-2",
|
|
98
|
+
LINK_CLASSES[variant]
|
|
99
|
+
),
|
|
100
|
+
children: action
|
|
101
|
+
}
|
|
102
|
+
)
|
|
80
103
|
] }),
|
|
81
104
|
closable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
82
105
|
Button.Button,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Alert.cjs","sources":["../../../../src/components/Alert/Alert.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\nimport { CheckCircleIcon } from \"../Icons/CheckCircleIcon\";\nimport { CrossIcon } from \"../Icons/CrossIcon\";\nimport { ErrorCircleIcon } from \"../Icons/ErrorCircleIcon\";\nimport { InfoCircleIcon } from \"../Icons/InfoCircleIcon\";\nimport { WarningTriangleIcon } from \"../Icons/WarningTriangleIcon\";\n\n/** Visual style variant of the alert. */\nexport type AlertVariant = \"info\" | \"success\" | \"warning\" | \"error\";\n\nconst DEFAULT_ICONS: Record<AlertVariant, React.ReactNode> = {\n info: <InfoCircleIcon />,\n success: <CheckCircleIcon />,\n warning: <WarningTriangleIcon />,\n error: <ErrorCircleIcon />,\n};\n\nexport interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Visual style variant of the alert. @default \"info\" */\n variant?: AlertVariant;\n /** Optional title text displayed in bold above the description. */\n title?: string;\n /** Custom icon override. Pass `null` to hide the icon entirely. Each variant shows a default icon when left `undefined`. */\n icon?: React.ReactNode | null;\n /** Whether to show the close button. @default false */\n closable?: boolean;\n /** Callback fired when the close button is clicked. */\n onClose?: () => void;\n /** Accessible label for the close button. @default \"Close alert\" */\n closeLabel?: string;\n}\n\nconst CLOSE_BUTTON_CLASSES: Record<AlertVariant, string> = {\n info: \"hover:bg-info-content/10 active:bg-info-content/20 text-info-content motion-safe:transition-colors motion-safe:duration-150\",\n success:\n \"hover:bg-success-content/10 active:bg-success-content/20 text-success-content motion-safe:transition-colors motion-safe:duration-150\",\n warning:\n \"hover:bg-warning-content/10 active:bg-warning-content/20 text-warning-content motion-safe:transition-colors motion-safe:duration-150\",\n error:\n \"hover:bg-error-content/10 active:bg-error-content/20 text-error-content motion-safe:transition-colors motion-safe:duration-150\",\n};\n\n/**\n * Displays a contextual feedback message to the user.\n *\n * Supports `info`, `success`, `warning`, and `
|
|
1
|
+
{"version":3,"file":"Alert.cjs","sources":["../../../../src/components/Alert/Alert.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\nimport { CheckCircleIcon } from \"../Icons/CheckCircleIcon\";\nimport { CrossIcon } from \"../Icons/CrossIcon\";\nimport { ErrorCircleIcon } from \"../Icons/ErrorCircleIcon\";\nimport { InfoCircleIcon } from \"../Icons/InfoCircleIcon\";\nimport { WarningTriangleIcon } from \"../Icons/WarningTriangleIcon\";\n\n/** Visual style variant of the alert. */\nexport type AlertVariant = \"info\" | \"success\" | \"warning\" | \"error\" | \"neutral\";\n\nconst DEFAULT_ICONS: Record<AlertVariant, React.ReactNode> = {\n info: <InfoCircleIcon />,\n success: <CheckCircleIcon />,\n warning: <WarningTriangleIcon />,\n error: <ErrorCircleIcon />,\n neutral: <InfoCircleIcon />,\n};\n\nexport interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Visual style variant of the alert. @default \"info\" */\n variant?: AlertVariant;\n /** Optional title text displayed in bold above the description. */\n title?: string;\n /** Custom icon override. Pass `null` to hide the icon entirely. Each variant shows a default icon when left `undefined`. */\n icon?: React.ReactNode | null;\n /** Whether to show the close button. @default false */\n closable?: boolean;\n /** Callback fired when the close button is clicked. */\n onClose?: () => void;\n /** Accessible label for the close button. @default \"Close alert\" */\n closeLabel?: string;\n /**\n * Composable action slot rendered beneath the description, outside the\n * `role=\"alert\"` live region. Pass your own element (an `<a>`, a `next/link`\n * `<Link>`, or a `<Button>`) and it receives the variant-appropriate link\n * styling via the Radix `Slot` pattern while remaining a real link/button.\n */\n action?: React.ReactNode;\n}\n\nconst CLOSE_BUTTON_CLASSES: Record<AlertVariant, string> = {\n info: \"hover:bg-info-content/10 active:bg-info-content/20 text-info-content motion-safe:transition-colors motion-safe:duration-150\",\n success:\n \"hover:bg-success-content/10 active:bg-success-content/20 text-success-content motion-safe:transition-colors motion-safe:duration-150\",\n warning:\n \"hover:bg-warning-content/10 active:bg-warning-content/20 text-warning-content motion-safe:transition-colors motion-safe:duration-150\",\n error:\n \"hover:bg-error-content/10 active:bg-error-content/20 text-error-content motion-safe:transition-colors motion-safe:duration-150\",\n neutral:\n \"hover:bg-content-secondary/10 active:bg-content-secondary/20 text-content-secondary motion-safe:transition-colors motion-safe:duration-150\",\n};\n\nconst LINK_CLASSES: Record<AlertVariant, string> = {\n info: \"text-alerts-info-prompt-content-info\",\n success: \"text-alerts-info-prompt-content-success\",\n warning: \"text-alerts-info-prompt-content-warning\",\n error: \"text-alerts-info-prompt-content-error\",\n neutral: \"text-content-secondary\",\n};\n\n/**\n * Displays a contextual feedback message to the user.\n *\n * Supports `info`, `success`, `warning`, `error`, and `neutral` variants with a\n * default icon per variant, optional title, description, dismiss button, and an\n * optional composable `action` slot.\n *\n * Each variant renders a default icon automatically. Pass a custom `icon` to\n * override, or `icon={null}` to hide the icon entirely.\n *\n * Only the title and description live inside the `role=\"alert\"` live region.\n * The icon, `action`, and close button are rendered outside it so interactive\n * controls are announced and navigated consistently by screen readers.\n *\n * @example\n * ```tsx\n * <Alert variant=\"success\" title=\"Saved\" closable onClose={handleClose}>\n * Your changes have been saved.\n * </Alert>\n * ```\n *\n * @example\n * ```tsx\n * <Alert variant=\"neutral\" title=\"Heads up\" action={<a href=\"/docs\">Learn more</a>}>\n * A general notice with no specific sentiment.\n * </Alert>\n * ```\n *\n * @example\n * ```tsx\n * import Link from \"next/link\";\n *\n * <Alert variant=\"info\" title=\"Update available\" action={<Link href=\"/changelog\">See what's new</Link>}>\n * A new version is ready to install.\n * </Alert>\n * ```\n */\nexport const Alert = React.forwardRef<HTMLDivElement, AlertProps>(\n (\n {\n className,\n variant = \"info\",\n title,\n icon,\n closable = false,\n onClose,\n closeLabel = \"Close alert\",\n action,\n children,\n ...props\n },\n ref,\n ) => {\n const resolvedIcon = icon === null ? null : (icon ?? DEFAULT_ICONS[variant]);\n\n return (\n <div\n ref={ref}\n data-testid=\"alert\"\n className={cn(\n \"grid gap-x-3 rounded-xs p-4 text-sm leading-[18px]\",\n resolvedIcon && closable && \"grid-cols-[auto_1fr_auto]\",\n resolvedIcon && !closable && \"grid-cols-[auto_1fr]\",\n !resolvedIcon && closable && \"grid-cols-[1fr_auto]\",\n !resolvedIcon && !closable && \"grid-cols-[1fr]\",\n title && children ? \"items-start\" : \"items-center\",\n variant === \"info\" && \"bg-info-surface text-info-content\",\n variant === \"success\" && \"bg-success-surface text-success-content\",\n variant === \"warning\" && \"bg-warning-surface text-warning-content\",\n variant === \"error\" && \"bg-error-surface text-error-content\",\n variant === \"neutral\" &&\n \"bg-alerts-info-prompt-background-neutral text-alerts-info-prompt-icon-neutral\",\n className,\n )}\n {...props}\n >\n {resolvedIcon && (\n <span className=\"flex shrink-0 items-start h-full\" aria-hidden=\"true\">\n {resolvedIcon}\n </span>\n )}\n\n <div className=\"flex min-w-0 flex-col gap-2\">\n <div role=\"alert\" className=\"flex flex-col gap-2\">\n {title && (\n <div className=\"typography-body-small-14px-semibold text-content-primary\">\n {title}\n </div>\n )}\n <div className=\"typography-body-small-14px-regular text-content-primary\">\n {children}\n </div>\n </div>\n {action && (\n <Slot\n className={cn(\n \"typography-body-small-14px-semibold w-fit cursor-pointer underline underline-offset-2\",\n LINK_CLASSES[variant],\n )}\n >\n {action}\n </Slot>\n )}\n </div>\n\n {closable && (\n <Button\n variant=\"tertiary\"\n size=\"24\"\n onClick={onClose}\n className={cn(\"self-start px-0\", CLOSE_BUTTON_CLASSES[variant])}\n aria-label={closeLabel}\n >\n <CrossIcon />\n </Button>\n )}\n </div>\n );\n },\n);\n\nAlert.displayName = \"Alert\";\n"],"names":["InfoCircleIcon","CheckCircleIcon","WarningTriangleIcon","ErrorCircleIcon","React","jsxs","cn","jsx","Slot","Button","CrossIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,MAAM,gBAAuD;AAAA,EAC3D,qCAAOA,eAAAA,gBAAA,EAAe;AAAA,EACtB,wCAAUC,gBAAAA,iBAAA,EAAgB;AAAA,EAC1B,wCAAUC,oBAAAA,qBAAA,EAAoB;AAAA,EAC9B,sCAAQC,gBAAAA,iBAAA,EAAgB;AAAA,EACxB,wCAAUH,eAAAA,gBAAA,CAAA,CAAe;AAC3B;AAwBA,MAAM,uBAAqD;AAAA,EACzD,MAAM;AAAA,EACN,SACE;AAAA,EACF,SACE;AAAA,EACF,OACE;AAAA,EACF,SACE;AACJ;AAEA,MAAM,eAA6C;AAAA,EACjD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AACX;AAuCO,MAAM,QAAQI,iBAAM;AAAA,EACzB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,eAAe,SAAS,OAAO,OAAQ,QAAQ,cAAc,OAAO;AAE1E,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAWC,GAAAA;AAAAA,UACT;AAAA,UACA,gBAAgB,YAAY;AAAA,UAC5B,gBAAgB,CAAC,YAAY;AAAA,UAC7B,CAAC,gBAAgB,YAAY;AAAA,UAC7B,CAAC,gBAAgB,CAAC,YAAY;AAAA,UAC9B,SAAS,WAAW,gBAAgB;AAAA,UACpC,YAAY,UAAU;AAAA,UACtB,YAAY,aAAa;AAAA,UACzB,YAAY,aAAa;AAAA,UACzB,YAAY,WAAW;AAAA,UACvB,YAAY,aACV;AAAA,UACF;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,+CACE,QAAA,EAAK,WAAU,oCAAmC,eAAY,QAC5D,UAAA,cACH;AAAA,UAGFD,2BAAAA,KAAC,OAAA,EAAI,WAAU,+BACb,UAAA;AAAA,YAAAA,2BAAAA,KAAC,OAAA,EAAI,MAAK,SAAQ,WAAU,uBACzB,UAAA;AAAA,cAAA,SACCE,2BAAAA,IAAC,OAAA,EAAI,WAAU,4DACZ,UAAA,OACH;AAAA,cAEFA,2BAAAA,IAAC,OAAA,EAAI,WAAU,2DACZ,SAAA,CACH;AAAA,YAAA,GACF;AAAA,YACC,UACCA,2BAAAA;AAAAA,cAACC,UAAAA;AAAAA,cAAA;AAAA,gBACC,WAAWF,GAAAA;AAAAA,kBACT;AAAA,kBACA,aAAa,OAAO;AAAA,gBAAA;AAAA,gBAGrB,UAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACH,GAEJ;AAAA,UAEC,YACCC,2BAAAA;AAAAA,YAACE,OAAAA;AAAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAWH,GAAAA,GAAG,mBAAmB,qBAAqB,OAAO,CAAC;AAAA,cAC9D,cAAY;AAAA,cAEZ,yCAACI,UAAAA,WAAA,CAAA,CAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACb;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,MAAM,cAAc;;"}
|
|
@@ -26,11 +26,17 @@ const badgeVariants = {
|
|
|
26
26
|
variant: {
|
|
27
27
|
default: "bg-neutral-alphas-50 text-content-primary",
|
|
28
28
|
dark: "bg-neutral-alphas-600 text-content-always-white",
|
|
29
|
-
success: "bg-
|
|
30
|
-
warning: "bg-
|
|
31
|
-
error: "bg-
|
|
29
|
+
success: "bg-success-surface text-success-content",
|
|
30
|
+
warning: "bg-warning-surface text-warning-content",
|
|
31
|
+
error: "bg-error-surface text-error-content",
|
|
32
32
|
special: "bg-neutral-alphas-50 text-content-primary",
|
|
33
|
-
info: "bg-
|
|
33
|
+
info: "bg-info-surface text-info-content",
|
|
34
|
+
successColour: "bg-success-surface text-content-primary",
|
|
35
|
+
warningColour: "bg-warning-surface text-content-primary",
|
|
36
|
+
errorColour: "bg-error-surface text-content-primary",
|
|
37
|
+
infoColour: "bg-info-surface text-content-primary",
|
|
38
|
+
aiGenerated: "bg-buttons-always-white-default text-content-always-black",
|
|
39
|
+
negative: "bg-buttons-secondary-negative-default text-content-primary-inverted",
|
|
34
40
|
online: "bg-background-primary text-brand-primary-default",
|
|
35
41
|
brand: "bg-brand-primary-default text-content-always-black",
|
|
36
42
|
pink: "bg-brand-secondary-default text-content-always-black",
|
|
@@ -45,6 +51,12 @@ const badgeVariants = {
|
|
|
45
51
|
error: "bg-error-content",
|
|
46
52
|
special: "bg-special-default",
|
|
47
53
|
info: "bg-info-content",
|
|
54
|
+
successColour: "bg-success-content",
|
|
55
|
+
warningColour: "bg-warning-content",
|
|
56
|
+
errorColour: "bg-error-content",
|
|
57
|
+
infoColour: "bg-info-content",
|
|
58
|
+
aiGenerated: "bg-content-always-black",
|
|
59
|
+
negative: "bg-icons-primary-inverted",
|
|
48
60
|
online: "bg-brand-primary-default",
|
|
49
61
|
brand: "bg-content-always-black",
|
|
50
62
|
pink: "bg-content-always-black",
|
|
@@ -72,7 +84,7 @@ const Badge = React__namespace.forwardRef(
|
|
|
72
84
|
"data-testid": "badge",
|
|
73
85
|
className: cn.cn(
|
|
74
86
|
// Base styles
|
|
75
|
-
"typography-description-12px-semibold inline-flex h-
|
|
87
|
+
"typography-description-12px-semibold inline-flex h-6 min-w-0 items-center gap-2 rounded-full px-2",
|
|
76
88
|
// Variant styles
|
|
77
89
|
badgeVariants.variant[variant],
|
|
78
90
|
// Interactive
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.cjs","sources":["../../../../src/components/Badge/Badge.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst badgeVariants = {\n variant: {\n default: \"bg-neutral-alphas-50 text-content-primary\",\n dark: \"bg-neutral-alphas-600 text-content-always-white\",\n success: \"bg-
|
|
1
|
+
{"version":3,"file":"Badge.cjs","sources":["../../../../src/components/Badge/Badge.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst badgeVariants = {\n variant: {\n default: \"bg-neutral-alphas-50 text-content-primary\",\n dark: \"bg-neutral-alphas-600 text-content-always-white\",\n success: \"bg-success-surface text-success-content\",\n warning: \"bg-warning-surface text-warning-content\",\n error: \"bg-error-surface text-error-content\",\n special: \"bg-neutral-alphas-50 text-content-primary\",\n info: \"bg-info-surface text-info-content\",\n successColour: \"bg-success-surface text-content-primary\",\n warningColour: \"bg-warning-surface text-content-primary\",\n errorColour: \"bg-error-surface text-content-primary\",\n infoColour: \"bg-info-surface text-content-primary\",\n aiGenerated: \"bg-buttons-always-white-default text-content-always-black\",\n negative: \"bg-buttons-secondary-negative-default text-content-primary-inverted\",\n online: \"bg-background-primary text-brand-primary-default\",\n brand: \"bg-brand-primary-default text-content-always-black\",\n pink: \"bg-brand-secondary-default text-content-always-black\",\n brandLight: \"bg-brand-primary-muted text-content-primary\",\n pinkLight: \"bg-brand-secondary-muted text-content-primary\",\n },\n dotColor: {\n default: \"bg-content-primary\",\n dark: \"bg-content-always-white\",\n success: \"bg-success-content\",\n warning: \"bg-warning-content\",\n error: \"bg-error-content\",\n special: \"bg-special-default\",\n info: \"bg-info-content\",\n successColour: \"bg-success-content\",\n warningColour: \"bg-warning-content\",\n errorColour: \"bg-error-content\",\n infoColour: \"bg-info-content\",\n aiGenerated: \"bg-content-always-black\",\n negative: \"bg-icons-primary-inverted\",\n online: \"bg-brand-primary-default\",\n brand: \"bg-content-always-black\",\n pink: \"bg-content-always-black\",\n brandLight: \"bg-content-always-black\",\n pinkLight: \"bg-content-always-black\",\n },\n} as const;\n\n/** Visual style variant of the badge. */\nexport type BadgeVariant =\n | \"default\"\n | \"dark\"\n | \"success\"\n | \"warning\"\n | \"error\"\n | \"special\"\n | \"info\"\n | \"successColour\"\n | \"warningColour\"\n | \"errorColour\"\n | \"infoColour\"\n | \"aiGenerated\"\n | \"negative\"\n | \"online\"\n | \"brand\"\n | \"pink\"\n | \"brandLight\"\n | \"pinkLight\";\n\nexport interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Visual style variant of the badge. @default \"default\" */\n variant?: BadgeVariant;\n /** Whether to show a coloured status dot at the leading edge. @default true */\n leftDot?: boolean;\n /** Icon element displayed before the label. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed after the label. */\n rightIcon?: React.ReactNode;\n /** Merge props onto a child element instead of rendering a `<span>`. @default false */\n asChild?: boolean;\n}\n\n/**\n * A small inline label for status, category, or metadata information.\n *\n * @example\n * ```tsx\n * <Badge variant=\"success\">Active</Badge>\n * ```\n */\nexport const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(\n (\n {\n className,\n variant = \"default\",\n leftDot = true,\n leftIcon,\n rightIcon,\n asChild = false,\n onClick,\n children,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"badge\"\n className={cn(\n // Base styles\n \"typography-description-12px-semibold inline-flex h-6 min-w-0 items-center gap-2 rounded-full px-2\",\n // Variant styles\n badgeVariants.variant[variant],\n // Interactive\n onClick && \"cursor-pointer\",\n // Manual CSS overrides\n className,\n )}\n onClick={onClick}\n {...props}\n >\n {leftIcon && (\n <span\n className=\"flex shrink-0 items-center justify-center [&>svg]:size-3\"\n aria-hidden=\"true\"\n >\n {leftIcon}\n </span>\n )}\n {leftDot && (\n <span\n className={cn(\"size-1 shrink-0 rounded-full\", badgeVariants.dotColor[variant])}\n aria-hidden=\"true\"\n />\n )}\n {asChild ? (\n <Slottable>{children}</Slottable>\n ) : (\n <span className=\"min-w-0 truncate\">{children}</span>\n )}\n {rightIcon && (\n <span\n className=\"flex shrink-0 items-center justify-center [&>svg]:size-3\"\n aria-hidden=\"true\"\n >\n {rightIcon}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nBadge.displayName = \"Badge\";\n"],"names":["React","Slot","jsxs","cn","jsx","Slottable"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,gBAAgB;AAAA,EACpB,SAAS;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EAAA;AAAA,EAEb,UAAU;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EAAA;AAEf;AA4CO,MAAM,QAAQA,iBAAM;AAAA,EACzB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,OAAO,UAAUC,UAAAA,OAAO;AAE9B,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAWC,GAAAA;AAAAA;AAAAA,UAET;AAAA;AAAA,UAEA,cAAc,QAAQ,OAAO;AAAA;AAAA,UAE7B,WAAW;AAAA;AAAA,UAEX;AAAA,QAAA;AAAA,QAEF;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,YACCC,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA,cAEX,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGJ,WACCA,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWD,GAAAA,GAAG,gCAAgC,cAAc,SAAS,OAAO,CAAC;AAAA,cAC7E,eAAY;AAAA,YAAA;AAAA,UAAA;AAAA,UAGf,yCACEE,qBAAA,EAAW,SAAA,CAAS,IAErBD,+BAAC,QAAA,EAAK,WAAU,oBAAoB,SAAA,CAAS;AAAA,UAE9C,aACCA,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA,cAEX,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,MAAM,cAAc;;"}
|
|
@@ -91,7 +91,7 @@ const Checkbox = React__namespace.forwardRef(
|
|
|
91
91
|
onCheckedChange: handleCheckedChange,
|
|
92
92
|
className: cn.cn(
|
|
93
93
|
// Base styles
|
|
94
|
-
"flex items-center justify-center rounded border
|
|
94
|
+
"flex items-center justify-center rounded border",
|
|
95
95
|
BOX_SIZE_CLASS[boxSize],
|
|
96
96
|
"transition-[border-color,background-color,color,box-shadow] duration-150",
|
|
97
97
|
// Default state
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.cjs","sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { MinusIcon } from \"../Icons/MinusIcon\";\n\n/**\n * Size variant for the checkbox.\n *\n * - `\"20\"` (default) — 20px box, body-lg label.\n * - `\"16\"` — 16px box, body-md label, used in compact contexts like data tables.\n * - `\"default\"` and `\"small\"` are legacy aliases retained for back-compat\n * (`\"default\"` → `\"20\"`, `\"small\"` → `\"20\"` with smaller label typography).\n */\nexport type CheckboxSize =\n | \"20\"\n | \"16\"\n /** @deprecated Use `\"20\"` instead. */\n | \"default\"\n /** @deprecated Use `\"20\"` (the smaller-typography variant remains via `\"small\"`). */\n | \"small\";\n\nconst BOX_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-5\",\n \"16\": \"size-4\",\n};\n\nconst INDICATOR_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-3\",\n \"16\": \"size-2.5\",\n};\n\nexport interface CheckboxProps\n extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, \"asChild\"> {\n /** Size variant. @default \"20\" */\n size?: CheckboxSize;\n /** Label text displayed next to the checkbox. */\n label?: string;\n /** Descriptive text displayed below the label. */\n helperText?: string;\n}\n\n/**\n * A checkbox input with optional label and helper text. Supports checked,\n * unchecked, and indeterminate states.\n *\n * The ref type is intentionally `HTMLInputElement` (not `HTMLButtonElement`) for\n * form-library compatibility — libraries like react-hook-form call `register()`\n * which expects an `HTMLInputElement` ref. A hidden `<input>` is synced to the\n * Radix checkbox state via `useImperativeHandle`.\n *\n * @example\n * ```tsx\n * <Checkbox label=\"Accept terms\" helperText=\"Required to continue\" />\n * ```\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ className, size = \"20\", label, helperText, disabled, name, ...props }, ref) => {\n const id = React.useId();\n const helperTextId = helperText ? `${id}-helper` : undefined;\n const hasLabel = Boolean(label || helperText);\n const boxSize: \"20\" | \"16\" = size === \"16\" ? \"16\" : \"20\";\n const useSmallLabelTypography = size === \"small\";\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n !label &&\n !props[\"aria-label\"] &&\n !props[\"aria-labelledby\"]\n ) {\n console.warn(\n \"Checkbox: No accessible name provided. Add a `label`, `aria-label`, or `aria-labelledby` prop so screen readers can announce this checkbox.\",\n );\n }\n\n // Hidden input for form library compatibility (e.g. react-hook-form register)\n const inputRef = React.useRef<HTMLInputElement>(null);\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);\n\n const handleCheckedChange = (value: boolean | \"indeterminate\") => {\n const checked = value === true;\n if (inputRef.current) {\n inputRef.current.checked = checked;\n inputRef.current.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n props.onCheckedChange?.(value);\n };\n\n const checkboxElement = (\n <span\n className={cn(\n \"relative inline-flex shrink-0\",\n BOX_SIZE_CLASS[boxSize],\n // Alignment when used with label\n label && (helperText ? \"mt-1\" : \"mt-0.5\"),\n )}\n >\n <input\n ref={inputRef}\n type=\"checkbox\"\n name={name}\n disabled={disabled}\n aria-hidden\n tabIndex={-1}\n onChange={() => {}}\n className=\"pointer-events-none absolute size-px overflow-hidden opacity-0\"\n style={{ clip: \"rect(0,0,0,0)\" }}\n />\n <CheckboxPrimitive.Root\n id={id}\n disabled={disabled}\n aria-describedby={helperTextId}\n data-testid=\"checkbox\"\n {...props}\n onCheckedChange={handleCheckedChange}\n className={cn(\n // Base styles\n \"flex items-center justify-center rounded border-2\",\n BOX_SIZE_CLASS[boxSize],\n \"transition-[border-color,background-color,color,box-shadow] duration-150\",\n // Default state\n \"border-content-primary bg-transparent text-transparent\",\n // Checked state\n \"data-[state=checked]:border-content-primary data-[state=checked]:bg-content-primary data-[state=checked]:text-content-primary-inverted\",\n // Indeterminate state\n \"data-[state=indeterminate]:border-content-primary data-[state=indeterminate]:bg-content-primary data-[state=indeterminate]:text-content-primary-inverted\",\n // Hover & active state\n \"hover:ring-2 hover:ring-brand-primary-default group-hover:ring-2 group-hover:ring-brand-primary-default\",\n \"not-disabled:active:ring-2 not-disabled:active:ring-brand-primary-default\",\n // Focus state\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled state\n \"disabled:cursor-not-allowed disabled:border-neutral-alphas-600 disabled:ring-0 disabled:group-hover:ring-0\",\n \"disabled:data-[state=checked]:border-neutral-alphas-600 disabled:data-[state=checked]:bg-neutral-alphas-600 disabled:data-[state=checked]:text-content-tertiary\",\n !hasLabel && className,\n )}\n >\n <CheckboxPrimitive.Indicator\n forceMount\n className={cn(\n \"flex items-center justify-center text-content-primary-inverted\",\n INDICATOR_SIZE_CLASS[boxSize],\n \"data-[state=unchecked]:invisible\",\n )}\n >\n {props.checked === \"indeterminate\" ? <MinusIcon /> : <CheckIcon />}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n </span>\n );\n\n if (!hasLabel) {\n return checkboxElement;\n }\n\n return (\n <div\n className={cn(\n \"inline-flex flex-col gap-0.5\",\n disabled && \"is-disabled cursor-not-allowed\",\n className,\n )}\n >\n <div className=\"group inline-flex items-start gap-2\">\n {checkboxElement}\n {label && (\n <label\n htmlFor={id}\n className={cn(\n \"cursor-pointer select-none text-content-primary\",\n \"group-has-disabled:cursor-not-allowed group-has-disabled:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\",\n )}\n >\n {label}\n </label>\n )}\n </div>\n {helperText && (\n <span\n id={helperTextId}\n className={cn(\n \"ml-7 text-content-secondary\",\n \"in-[.is-disabled]:cursor-not-allowed in-[.is-disabled]:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-description-12px-regular\"\n : \"typography-body-small-14px-regular\",\n )}\n >\n {helperText}\n </span>\n )}\n </div>\n );\n },\n);\n\nCheckbox.displayName = \"Checkbox\";\n"],"names":["React","jsxs","cn","jsx","CheckboxPrimitive","MinusIcon","CheckIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Checkbox.cjs","sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { MinusIcon } from \"../Icons/MinusIcon\";\n\n/**\n * Size variant for the checkbox.\n *\n * - `\"20\"` (default) — 20px box, body-lg label.\n * - `\"16\"` — 16px box, body-md label, used in compact contexts like data tables.\n * - `\"default\"` and `\"small\"` are legacy aliases retained for back-compat\n * (`\"default\"` → `\"20\"`, `\"small\"` → `\"20\"` with smaller label typography).\n */\nexport type CheckboxSize =\n | \"20\"\n | \"16\"\n /** @deprecated Use `\"20\"` instead. */\n | \"default\"\n /** @deprecated Use `\"20\"` (the smaller-typography variant remains via `\"small\"`). */\n | \"small\";\n\nconst BOX_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-5\",\n \"16\": \"size-4\",\n};\n\nconst INDICATOR_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-3\",\n \"16\": \"size-2.5\",\n};\n\nexport interface CheckboxProps\n extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, \"asChild\"> {\n /** Size variant. @default \"20\" */\n size?: CheckboxSize;\n /** Label text displayed next to the checkbox. */\n label?: string;\n /** Descriptive text displayed below the label. */\n helperText?: string;\n}\n\n/**\n * A checkbox input with optional label and helper text. Supports checked,\n * unchecked, and indeterminate states.\n *\n * The ref type is intentionally `HTMLInputElement` (not `HTMLButtonElement`) for\n * form-library compatibility — libraries like react-hook-form call `register()`\n * which expects an `HTMLInputElement` ref. A hidden `<input>` is synced to the\n * Radix checkbox state via `useImperativeHandle`.\n *\n * @example\n * ```tsx\n * <Checkbox label=\"Accept terms\" helperText=\"Required to continue\" />\n * ```\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ className, size = \"20\", label, helperText, disabled, name, ...props }, ref) => {\n const id = React.useId();\n const helperTextId = helperText ? `${id}-helper` : undefined;\n const hasLabel = Boolean(label || helperText);\n const boxSize: \"20\" | \"16\" = size === \"16\" ? \"16\" : \"20\";\n const useSmallLabelTypography = size === \"small\";\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n !label &&\n !props[\"aria-label\"] &&\n !props[\"aria-labelledby\"]\n ) {\n console.warn(\n \"Checkbox: No accessible name provided. Add a `label`, `aria-label`, or `aria-labelledby` prop so screen readers can announce this checkbox.\",\n );\n }\n\n // Hidden input for form library compatibility (e.g. react-hook-form register)\n const inputRef = React.useRef<HTMLInputElement>(null);\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);\n\n const handleCheckedChange = (value: boolean | \"indeterminate\") => {\n const checked = value === true;\n if (inputRef.current) {\n inputRef.current.checked = checked;\n inputRef.current.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n props.onCheckedChange?.(value);\n };\n\n const checkboxElement = (\n <span\n className={cn(\n \"relative inline-flex shrink-0\",\n BOX_SIZE_CLASS[boxSize],\n // Alignment when used with label\n label && (helperText ? \"mt-1\" : \"mt-0.5\"),\n )}\n >\n <input\n ref={inputRef}\n type=\"checkbox\"\n name={name}\n disabled={disabled}\n aria-hidden\n tabIndex={-1}\n onChange={() => {}}\n className=\"pointer-events-none absolute size-px overflow-hidden opacity-0\"\n style={{ clip: \"rect(0,0,0,0)\" }}\n />\n <CheckboxPrimitive.Root\n id={id}\n disabled={disabled}\n aria-describedby={helperTextId}\n data-testid=\"checkbox\"\n {...props}\n onCheckedChange={handleCheckedChange}\n className={cn(\n // Base styles\n \"flex items-center justify-center rounded border\",\n BOX_SIZE_CLASS[boxSize],\n \"transition-[border-color,background-color,color,box-shadow] duration-150\",\n // Default state\n \"border-content-primary bg-transparent text-transparent\",\n // Checked state\n \"data-[state=checked]:border-content-primary data-[state=checked]:bg-content-primary data-[state=checked]:text-content-primary-inverted\",\n // Indeterminate state\n \"data-[state=indeterminate]:border-content-primary data-[state=indeterminate]:bg-content-primary data-[state=indeterminate]:text-content-primary-inverted\",\n // Hover & active state\n \"hover:ring-2 hover:ring-brand-primary-default group-hover:ring-2 group-hover:ring-brand-primary-default\",\n \"not-disabled:active:ring-2 not-disabled:active:ring-brand-primary-default\",\n // Focus state\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled state\n \"disabled:cursor-not-allowed disabled:border-neutral-alphas-600 disabled:ring-0 disabled:group-hover:ring-0\",\n \"disabled:data-[state=checked]:border-neutral-alphas-600 disabled:data-[state=checked]:bg-neutral-alphas-600 disabled:data-[state=checked]:text-content-tertiary\",\n !hasLabel && className,\n )}\n >\n <CheckboxPrimitive.Indicator\n forceMount\n className={cn(\n \"flex items-center justify-center text-content-primary-inverted\",\n INDICATOR_SIZE_CLASS[boxSize],\n \"data-[state=unchecked]:invisible\",\n )}\n >\n {props.checked === \"indeterminate\" ? <MinusIcon /> : <CheckIcon />}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n </span>\n );\n\n if (!hasLabel) {\n return checkboxElement;\n }\n\n return (\n <div\n className={cn(\n \"inline-flex flex-col gap-0.5\",\n disabled && \"is-disabled cursor-not-allowed\",\n className,\n )}\n >\n <div className=\"group inline-flex items-start gap-2\">\n {checkboxElement}\n {label && (\n <label\n htmlFor={id}\n className={cn(\n \"cursor-pointer select-none text-content-primary\",\n \"group-has-disabled:cursor-not-allowed group-has-disabled:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\",\n )}\n >\n {label}\n </label>\n )}\n </div>\n {helperText && (\n <span\n id={helperTextId}\n className={cn(\n \"ml-7 text-content-secondary\",\n \"in-[.is-disabled]:cursor-not-allowed in-[.is-disabled]:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-description-12px-regular\"\n : \"typography-body-small-14px-regular\",\n )}\n >\n {helperText}\n </span>\n )}\n </div>\n );\n },\n);\n\nCheckbox.displayName = \"Checkbox\";\n"],"names":["React","jsxs","cn","jsx","CheckboxPrimitive","MinusIcon","CheckIcon"],"mappings":"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"}
|
|
@@ -57,6 +57,7 @@ const DialogContent = React__namespace.forwardRef(
|
|
|
57
57
|
overlay = true,
|
|
58
58
|
portal = true,
|
|
59
59
|
showMobileHandle = true,
|
|
60
|
+
mobilePresentation = "sheet",
|
|
60
61
|
style,
|
|
61
62
|
onOpenAutoFocus,
|
|
62
63
|
...props
|
|
@@ -78,21 +79,33 @@ const DialogContent = React__namespace.forwardRef(
|
|
|
78
79
|
},
|
|
79
80
|
className: cn.cn(
|
|
80
81
|
"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none",
|
|
81
|
-
"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3",
|
|
82
82
|
"data-[state=open]:fade-in-0 data-[state=open]:animate-in",
|
|
83
83
|
"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out",
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
mobilePresentation === "card" ? (
|
|
85
|
+
// Floating confirmation card (v2-modal): 16px side margins, vertically centered, 32px radius
|
|
86
|
+
cn.cn(
|
|
87
|
+
"inset-x-4 top-1/2 max-h-[85vh] -translate-y-1/2 rounded-xl p-6",
|
|
88
|
+
"data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95",
|
|
89
|
+
"sm:inset-x-auto"
|
|
90
|
+
)
|
|
91
|
+
) : (
|
|
92
|
+
// Bottom sheet pinned to the viewport bottom edge
|
|
93
|
+
cn.cn(
|
|
94
|
+
"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3",
|
|
95
|
+
"data-[state=open]:slide-in-from-bottom-full",
|
|
96
|
+
"data-[state=closed]:slide-out-to-bottom-full",
|
|
97
|
+
"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95",
|
|
98
|
+
"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95"
|
|
99
|
+
)
|
|
100
|
+
),
|
|
101
|
+
"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg sm:p-6",
|
|
89
102
|
"duration-200",
|
|
90
103
|
SIZE_CLASSES[size],
|
|
91
104
|
className
|
|
92
105
|
),
|
|
93
106
|
...props,
|
|
94
107
|
children: [
|
|
95
|
-
showMobileHandle && /* @__PURE__ */ jsxRuntime.jsx(
|
|
108
|
+
showMobileHandle && mobilePresentation === "sheet" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
109
|
"div",
|
|
97
110
|
{
|
|
98
111
|
"aria-hidden": "true",
|
|
@@ -173,7 +186,7 @@ const DialogDescription = React__namespace.forwardRef(({ className, ...props },
|
|
|
173
186
|
));
|
|
174
187
|
DialogDescription.displayName = "DialogDescription";
|
|
175
188
|
const DialogBody = React__namespace.forwardRef(
|
|
176
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn.cn("flex-1 overflow-y-auto py-4
|
|
189
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn.cn("flex-1 overflow-y-auto py-4", className), ...props })
|
|
177
190
|
);
|
|
178
191
|
DialogBody.displayName = "DialogBody";
|
|
179
192
|
const DialogFooter = React__namespace.forwardRef(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.cjs","sources":["../../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ArrowLeftIcon } from \"../Icons/ArrowLeftIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Props for the {@link Dialog} root component. */\nexport interface DialogProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /** Controlled open state. When provided, you must also supply `onOpenChange`. */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the dialog when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a dialog. */\nexport const Dialog = DialogPrimitive.Root;\n\n/** Props for the {@link DialogTrigger} component. */\nexport type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the dialog when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the dialog on a scroll-drag-end.\n */\nexport const DialogTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DialogTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDialogTrigger.displayName = \"DialogTrigger\";\n\n/** Convenience alias for Radix `Dialog.Close`. Closes the dialog when clicked. */\nexport const DialogClose = DialogPrimitive.Close;\n\n/** Props for the {@link DialogClose} component. */\nexport type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\nexport interface DialogOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * Semi-transparent backdrop rendered behind the dialog content.\n * Rendered by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\n */\nexport const DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-background-overlay-default data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className,\n )}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport interface DialogContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * Width preset for the dialog.\n * - `\"sm\"` — 400px max-width (confirmations, simple forms)\n * - `\"md\"` — 440px max-width (default, standard dialogs)\n * - `\"lg\"` — 600px max-width (complex content, tables)\n *\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** When true, renders overlay automatically. @default true */\n overlay?: boolean;\n /**\n * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n /** Show the v2 mobile sheet pull handle. @default true */\n showMobileHandle?: boolean;\n}\n\nconst SIZE_CLASSES: Record<NonNullable<DialogContentProps[\"size\"]>, string> = {\n sm: \"sm:max-w-[400px]\",\n md: \"sm:max-w-[440px]\",\n lg: \"sm:max-w-[600px]\",\n};\n\n/**\n * The dialog panel. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius. On larger viewports it renders centered with\n * full border radius.\n *\n * @example\n * ```tsx\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Title</DialogTitle>\n * </DialogHeader>\n * <DialogBody>Content here</DialogBody>\n * <DialogFooter>\n * <DialogClose asChild>\n * <Button variant=\"secondary\">Cancel</Button>\n * </DialogClose>\n * <Button>Accept</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n */\nexport const DialogContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n showMobileHandle = true,\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\n {overlay && <DialogOverlay />}\n <DialogPrimitive.Content\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n onOpenAutoFocus={(e) => {\n if (onOpenAutoFocus) {\n onOpenAutoFocus(e);\n return;\n }\n e.preventDefault();\n (e.currentTarget as HTMLElement).focus();\n }}\n className={cn(\n \"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none\",\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3\",\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-xl sm:p-6\",\n \"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95\",\n \"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {showMobileHandle && (\n <div\n aria-hidden=\"true\"\n className=\"mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden\"\n />\n )}\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\n);\nDialogContent.displayName = \"DialogContent\";\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Show the close (X) button in the header. @default true */\n showClose?: boolean;\n /** Show a back arrow button on the left side. Defaults to `true` when `onBack` is provided. */\n showBack?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible label for the back button. @default \"Go back\" */\n backLabel?: string;\n /** Accessible label for the close button. @default \"Close\" */\n closeLabel?: string;\n}\n\n/**\n * Header bar for the dialog. Renders the title with an optional back arrow\n * and close button.\n *\n * @example\n * ```tsx\n * <DialogHeader>\n * <DialogTitle>Settings</DialogTitle>\n * </DialogHeader>\n *\n * <DialogHeader showBack onBack={() => setStep(0)}>\n * <DialogTitle>Step 2</DialogTitle>\n * </DialogHeader>\n * ```\n */\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n (\n {\n className,\n children,\n showClose = true,\n showBack,\n onBack,\n backLabel = \"Go back\",\n closeLabel = \"Close\",\n ...props\n },\n ref,\n ) => {\n const shouldShowBack = showBack ?? !!onBack;\n\n return (\n <div\n ref={ref}\n className={cn(\"flex shrink-0 items-center justify-end gap-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<ArrowLeftIcon size={16} />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<CloseIcon size={16} />}\n aria-label={closeLabel}\n />\n </DialogPrimitive.Close>\n )}\n </div>\n );\n },\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Props for the {@link DialogTitle} component. */\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\n/**\n * Accessible title for the dialog. Must be rendered inside {@link DialogHeader}\n * or directly within {@link DialogContent}.\n */\nexport const DialogTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-header-heading-xs text-content-primary\", className)}\n {...props}\n />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Props for the {@link DialogDescription} component. */\nexport type DialogDescriptionProps = React.ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/** Accessible description for the dialog. Rendered as secondary text. */\nexport const DialogDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-default-16px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Scrollable content area (slot) between the header and footer.\n * Grows to fill available space and scrolls when content overflows.\n */\nexport const DialogBody = React.forwardRef<HTMLDivElement, DialogBodyProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex-1 overflow-y-auto py-4 sm:py-6\", className)} {...props} />\n ),\n);\nDialogBody.displayName = \"DialogBody\";\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Footer bar for the dialog. Typically contains action buttons.\n * Children are laid out in a horizontal row with equal flex-basis.\n */\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex shrink-0 items-center gap-2\", \"[&>*]:min-w-0 [&>*]:flex-1\", className)}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":["DialogPrimitive","React","jsx","useSuppressClickAfterDrag","cn","jsxs","Fragment","IconButton","ArrowLeftIcon","CloseIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dialog.cjs","sources":["../../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ArrowLeftIcon } from \"../Icons/ArrowLeftIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Props for the {@link Dialog} root component. */\nexport interface DialogProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /** Controlled open state. When provided, you must also supply `onOpenChange`. */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the dialog when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a dialog. */\nexport const Dialog = DialogPrimitive.Root;\n\n/** Props for the {@link DialogTrigger} component. */\nexport type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the dialog when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the dialog on a scroll-drag-end.\n */\nexport const DialogTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DialogTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDialogTrigger.displayName = \"DialogTrigger\";\n\n/** Convenience alias for Radix `Dialog.Close`. Closes the dialog when clicked. */\nexport const DialogClose = DialogPrimitive.Close;\n\n/** Props for the {@link DialogClose} component. */\nexport type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\nexport interface DialogOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * Semi-transparent backdrop rendered behind the dialog content.\n * Rendered by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\n */\nexport const DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-background-overlay-default data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className,\n )}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport interface DialogContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * Width preset for the dialog.\n * - `\"sm\"` — 400px max-width (confirmations, simple forms)\n * - `\"md\"` — 440px max-width (default, standard dialogs)\n * - `\"lg\"` — 600px max-width (complex content, tables)\n *\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** When true, renders overlay automatically. @default true */\n overlay?: boolean;\n /**\n * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n /** Show the v2 mobile sheet pull handle. Only rendered when `mobilePresentation` is `\"sheet\"`. @default true */\n showMobileHandle?: boolean;\n /**\n * How the dialog presents below the `sm` breakpoint.\n * - `\"sheet\"` — bottom sheet pinned to the viewport bottom edge (default)\n * - `\"card\"` — centered floating card per the v2-modal confirmation spec:\n * 16px side margins, 24px padding, 32px radius on all corners, no pull handle\n *\n * @default \"sheet\"\n */\n mobilePresentation?: \"sheet\" | \"card\";\n}\n\nconst SIZE_CLASSES: Record<NonNullable<DialogContentProps[\"size\"]>, string> = {\n sm: \"sm:max-w-[400px]\",\n md: \"sm:max-w-[440px]\",\n lg: \"sm:max-w-[600px]\",\n};\n\n/**\n * The dialog panel. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius by default; pass `mobilePresentation=\"card\"` to\n * render a centered floating card instead (used for small confirmation dialogs).\n * On larger viewports it renders centered with full border radius.\n *\n * @example\n * ```tsx\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Title</DialogTitle>\n * </DialogHeader>\n * <DialogBody>Content here</DialogBody>\n * <DialogFooter>\n * <DialogClose asChild>\n * <Button variant=\"secondary\">Cancel</Button>\n * </DialogClose>\n * <Button>Accept</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n */\nexport const DialogContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n showMobileHandle = true,\n mobilePresentation = \"sheet\",\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\n {overlay && <DialogOverlay />}\n <DialogPrimitive.Content\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n onOpenAutoFocus={(e) => {\n if (onOpenAutoFocus) {\n onOpenAutoFocus(e);\n return;\n }\n e.preventDefault();\n (e.currentTarget as HTMLElement).focus();\n }}\n className={cn(\n \"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none\",\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n mobilePresentation === \"card\"\n ? // Floating confirmation card (v2-modal): 16px side margins, vertically centered, 32px radius\n cn(\n \"inset-x-4 top-1/2 max-h-[85vh] -translate-y-1/2 rounded-xl p-6\",\n \"data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95\",\n \"sm:inset-x-auto\",\n )\n : // Bottom sheet pinned to the viewport bottom edge\n cn(\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\n \"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95\",\n \"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95\",\n ),\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg sm:p-6\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {showMobileHandle && mobilePresentation === \"sheet\" && (\n <div\n aria-hidden=\"true\"\n className=\"mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden\"\n />\n )}\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\n);\nDialogContent.displayName = \"DialogContent\";\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Show the close (X) button in the header. @default true */\n showClose?: boolean;\n /** Show a back arrow button on the left side. Defaults to `true` when `onBack` is provided. */\n showBack?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible label for the back button. @default \"Go back\" */\n backLabel?: string;\n /** Accessible label for the close button. @default \"Close\" */\n closeLabel?: string;\n}\n\n/**\n * Header bar for the dialog. Renders the title with an optional back arrow\n * and close button.\n *\n * @example\n * ```tsx\n * <DialogHeader>\n * <DialogTitle>Settings</DialogTitle>\n * </DialogHeader>\n *\n * <DialogHeader showBack onBack={() => setStep(0)}>\n * <DialogTitle>Step 2</DialogTitle>\n * </DialogHeader>\n * ```\n */\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n (\n {\n className,\n children,\n showClose = true,\n showBack,\n onBack,\n backLabel = \"Go back\",\n closeLabel = \"Close\",\n ...props\n },\n ref,\n ) => {\n const shouldShowBack = showBack ?? !!onBack;\n\n return (\n <div\n ref={ref}\n className={cn(\"flex shrink-0 items-center justify-end gap-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<ArrowLeftIcon size={16} />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<CloseIcon size={16} />}\n aria-label={closeLabel}\n />\n </DialogPrimitive.Close>\n )}\n </div>\n );\n },\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Props for the {@link DialogTitle} component. */\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\n/**\n * Accessible title for the dialog. Must be rendered inside {@link DialogHeader}\n * or directly within {@link DialogContent}.\n */\nexport const DialogTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-header-heading-xs text-content-primary\", className)}\n {...props}\n />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Props for the {@link DialogDescription} component. */\nexport type DialogDescriptionProps = React.ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/** Accessible description for the dialog. Rendered as secondary text. */\nexport const DialogDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-default-16px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Scrollable content area (slot) between the header and footer.\n * Grows to fill available space and scrolls when content overflows.\n */\nexport const DialogBody = React.forwardRef<HTMLDivElement, DialogBodyProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex-1 overflow-y-auto py-4\", className)} {...props} />\n ),\n);\nDialogBody.displayName = \"DialogBody\";\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Footer bar for the dialog. Typically contains action buttons.\n * Children are laid out in a horizontal row with equal flex-basis.\n */\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex shrink-0 items-center gap-2\", \"[&>*]:min-w-0 [&>*]:flex-1\", className)}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":["DialogPrimitive","React","jsx","useSuppressClickAfterDrag","cn","jsxs","Fragment","IconButton","ArrowLeftIcon","CloseIcon"],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const React = require("react");
|
|
6
|
+
const cn = require("../../utils/cn.cjs");
|
|
7
|
+
const DiamondIcon = require("../Icons/DiamondIcon.cjs");
|
|
8
|
+
const HeartIcon = require("../Icons/HeartIcon.cjs");
|
|
9
|
+
function _interopNamespaceDefault(e) {
|
|
10
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
11
|
+
if (e) {
|
|
12
|
+
for (const k in e) {
|
|
13
|
+
if (k !== "default") {
|
|
14
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: () => e[k]
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
26
|
+
const compactFormatter = new Intl.NumberFormat("en", {
|
|
27
|
+
notation: "compact",
|
|
28
|
+
maximumFractionDigits: 1
|
|
29
|
+
});
|
|
30
|
+
function formatCount(value) {
|
|
31
|
+
return typeof value === "number" ? compactFormatter.format(value).toLowerCase() : value;
|
|
32
|
+
}
|
|
33
|
+
const FanFollowerCount = React__namespace.forwardRef(
|
|
34
|
+
({
|
|
35
|
+
className,
|
|
36
|
+
fans = 0,
|
|
37
|
+
subs = 0,
|
|
38
|
+
showFans = true,
|
|
39
|
+
showSubs = true,
|
|
40
|
+
fansLabel = "Fans",
|
|
41
|
+
subsLabel = "Subs",
|
|
42
|
+
...props
|
|
43
|
+
}, ref) => {
|
|
44
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn.cn("inline-flex items-center gap-3", className), ...props, children: [
|
|
45
|
+
showFans && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
|
|
46
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeartIcon.HeartIcon, { size: 16, filled: true, className: "text-icons-tertiary" }),
|
|
47
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typography-body-small-14px-semibold inline-flex items-center gap-1 text-content-primary", children: [
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatCount(fans) }),
|
|
49
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: fansLabel })
|
|
50
|
+
] })
|
|
51
|
+
] }),
|
|
52
|
+
showSubs && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
|
|
53
|
+
/* @__PURE__ */ jsxRuntime.jsx(DiamondIcon.DiamondIcon, { size: 16, filled: true, className: "text-icons-tertiary" }),
|
|
54
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typography-body-small-14px-semibold inline-flex items-center gap-1 text-content-primary", children: [
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatCount(subs) }),
|
|
56
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: subsLabel })
|
|
57
|
+
] })
|
|
58
|
+
] })
|
|
59
|
+
] });
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
FanFollowerCount.displayName = "FanFollowerCount";
|
|
63
|
+
exports.FanFollowerCount = FanFollowerCount;
|
|
64
|
+
//# sourceMappingURL=FanFollowerCount.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FanFollowerCount.cjs","sources":["../../../../src/components/FanFollowerCount/FanFollowerCount.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { DiamondIcon } from \"../Icons/DiamondIcon\";\nimport { HeartIcon } from \"../Icons/HeartIcon\";\n\nconst compactFormatter = new Intl.NumberFormat(\"en\", {\n notation: \"compact\",\n maximumFractionDigits: 1,\n});\n\nfunction formatCount(value: number | string): string {\n return typeof value === \"number\" ? compactFormatter.format(value).toLowerCase() : value;\n}\n\nexport interface FanFollowerCountProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Fan count. Numbers are compacted (e.g. `1200` → `\"1.2k\"`); strings render verbatim. @default 0 */\n fans?: number | string;\n /** Subscriber count. Numbers are compacted (e.g. `3000` → `\"3k\"`); strings render verbatim. @default 0 */\n subs?: number | string;\n /** Show the fan count group. @default true */\n showFans?: boolean;\n /** Show the subscriber count group. @default true */\n showSubs?: boolean;\n /** Label rendered after the fan count. @default \"Fans\" */\n fansLabel?: string;\n /** Label rendered after the subscriber count. @default \"Subs\" */\n subsLabel?: string;\n}\n\n/**\n * Displays a creator's formatted fan and subscriber counts, each paired with an\n * icon. Numeric values are compacted (`1200` → `\"1.2k\"`); pass a pre-formatted\n * string to bypass formatting. Either group can be hidden independently.\n *\n * @example\n * ```tsx\n * <FanFollowerCount fans={1200} subs={3000} />\n * ```\n */\nexport const FanFollowerCount = React.forwardRef<HTMLDivElement, FanFollowerCountProps>(\n (\n {\n className,\n fans = 0,\n subs = 0,\n showFans = true,\n showSubs = true,\n fansLabel = \"Fans\",\n subsLabel = \"Subs\",\n ...props\n },\n ref,\n ) => {\n return (\n <div ref={ref} className={cn(\"inline-flex items-center gap-3\", className)} {...props}>\n {showFans && (\n <span className=\"inline-flex items-center gap-2\">\n <HeartIcon size={16} filled className=\"text-icons-tertiary\" />\n <span className=\"typography-body-small-14px-semibold inline-flex items-center gap-1 text-content-primary\">\n <span>{formatCount(fans)}</span>\n <span>{fansLabel}</span>\n </span>\n </span>\n )}\n {showSubs && (\n <span className=\"inline-flex items-center gap-2\">\n <DiamondIcon size={16} filled className=\"text-icons-tertiary\" />\n <span className=\"typography-body-small-14px-semibold inline-flex items-center gap-1 text-content-primary\">\n <span>{formatCount(subs)}</span>\n <span>{subsLabel}</span>\n </span>\n </span>\n )}\n </div>\n );\n },\n);\n\nFanFollowerCount.displayName = \"FanFollowerCount\";\n"],"names":["React","jsxs","cn","jsx","HeartIcon","DiamondIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAM,mBAAmB,IAAI,KAAK,aAAa,MAAM;AAAA,EACnD,UAAU;AAAA,EACV,uBAAuB;AACzB,CAAC;AAED,SAAS,YAAY,OAAgC;AACnD,SAAO,OAAO,UAAU,WAAW,iBAAiB,OAAO,KAAK,EAAE,gBAAgB;AACpF;AA2BO,MAAM,mBAAmBA,iBAAM;AAAA,EACpC,CACE;AAAA,IACE;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,GAAG;AAAA,EAAA,GAEL,QACG;AACH,WACEC,gCAAC,SAAI,KAAU,WAAWC,MAAG,kCAAkC,SAAS,GAAI,GAAG,OAC5E,UAAA;AAAA,MAAA,YACCD,2BAAAA,KAAC,QAAA,EAAK,WAAU,kCACd,UAAA;AAAA,QAAAE,+BAACC,UAAAA,aAAU,MAAM,IAAI,QAAM,MAAC,WAAU,uBAAsB;AAAA,QAC5DH,2BAAAA,KAAC,QAAA,EAAK,WAAU,2FACd,UAAA;AAAA,UAAAE,2BAAAA,IAAC,QAAA,EAAM,UAAA,YAAY,IAAI,EAAA,CAAE;AAAA,UACzBA,2BAAAA,IAAC,UAAM,UAAA,UAAA,CAAU;AAAA,QAAA,EAAA,CACnB;AAAA,MAAA,GACF;AAAA,MAED,YACCF,2BAAAA,KAAC,QAAA,EAAK,WAAU,kCACd,UAAA;AAAA,QAAAE,+BAACE,YAAAA,eAAY,MAAM,IAAI,QAAM,MAAC,WAAU,uBAAsB;AAAA,QAC9DJ,2BAAAA,KAAC,QAAA,EAAK,WAAU,2FACd,UAAA;AAAA,UAAAE,2BAAAA,IAAC,QAAA,EAAM,UAAA,YAAY,IAAI,EAAA,CAAE;AAAA,UACzBA,2BAAAA,IAAC,UAAM,UAAA,UAAA,CAAU;AAAA,QAAA,EAAA,CACnB;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GAEJ;AAAA,EAEJ;AACF;AAEA,iBAAiB,cAAc;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.cjs","sources":["../../../../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Count, type CountSize } from \"../Count/Count\";\n\nconst iconButtonVariants = {\n primary:\n \"bg-buttons-primary-default text-content-primary-inverted hover:bg-buttons-primary-hover not-disabled:active:bg-buttons-primary-hover disabled:opacity-50 focus-visible:shadow-focus-ring\",\n secondary:\n \"bg-neutral-alphas-50 text-icons-primary hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiary:\n \"bg-transparent text-content-primary hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n brand:\n \"bg-content-always-black text-brand-primary-default hover:bg-brand-primary-default hover:text-content-always-black not-disabled:active:bg-brand-primary-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n contrast:\n \"bg-transparent text-content-always-white hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n messaging:\n \"bg-content-always-black text-brand-primary-default hover:bg-brand-primary-default hover:text-content-always-black not-disabled:active:bg-brand-primary-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n navTray:\n \"bg-transparent text-content-primary hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiaryDestructive:\n \"bg-transparent text-error-content hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n stop: \"bg-buttons-primary-default text-content-primary-inverted hover:bg-buttons-brand-default hover:text-content-always-black not-disabled:active:bg-buttons-brand-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n microphone:\n \"bg-buttons-primary-default text-content-primary-inverted hover:bg-buttons-brand-default hover:text-content-always-black not-disabled:active:bg-buttons-brand-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n};\n\nconst iconSizeVariants = {\n 24: \"[&>svg]:size-4\",\n 32: \"[&>svg]:size-
|
|
1
|
+
{"version":3,"file":"IconButton.cjs","sources":["../../../../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Count, type CountSize } from \"../Count/Count\";\n\nconst iconButtonVariants = {\n primary:\n \"bg-buttons-primary-default text-content-primary-inverted hover:bg-buttons-primary-hover not-disabled:active:bg-buttons-primary-hover disabled:opacity-50 focus-visible:shadow-focus-ring\",\n secondary:\n \"bg-neutral-alphas-50 text-icons-primary hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiary:\n \"bg-transparent text-content-primary hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n brand:\n \"bg-content-always-black text-brand-primary-default hover:bg-brand-primary-default hover:text-content-always-black not-disabled:active:bg-brand-primary-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n contrast:\n \"bg-transparent text-content-always-white hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n messaging:\n \"bg-content-always-black text-brand-primary-default hover:bg-brand-primary-default hover:text-content-always-black not-disabled:active:bg-brand-primary-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n navTray:\n \"bg-transparent text-content-primary hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiaryDestructive:\n \"bg-transparent text-error-content hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted disabled:opacity-50 focus-visible:shadow-focus-ring\",\n stop: \"bg-buttons-primary-default text-content-primary-inverted hover:bg-buttons-brand-default hover:text-content-always-black not-disabled:active:bg-buttons-brand-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n microphone:\n \"bg-buttons-primary-default text-content-primary-inverted hover:bg-buttons-brand-default hover:text-content-always-black not-disabled:active:bg-buttons-brand-default not-disabled:active:text-content-always-black disabled:opacity-50 focus-visible:shadow-focus-ring\",\n};\n\nconst iconSizeVariants = {\n 24: \"[&>svg]:size-4\",\n 32: \"[&>svg]:size-4\",\n 40: \"[&>svg]:size-6\",\n 52: \"[&>svg]:size-7\",\n 72: \"[&>svg]:size-8\",\n} as const;\n\nconst sizeVariants = {\n 24: \"size-6 p-1\",\n 32: \"size-8 p-1.5\",\n 40: \"size-10 p-[10px]\",\n 52: \"size-[52px] p-2\",\n 72: \"size-[72px] p-4\",\n} as const;\n\nconst countSizeMap: Record<string, CountSize> = {\n 24: \"16\",\n 32: \"24\",\n 40: \"32\",\n 52: \"32\",\n 72: \"32\",\n};\n\n/** Visual style variant of the icon button. */\nexport type IconButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"tertiary\"\n | \"brand\"\n | \"contrast\"\n | \"messaging\"\n | \"navTray\"\n | \"tertiaryDestructive\"\n | \"stop\"\n | \"microphone\";\n\n/** Icon button size in pixels. */\nexport type IconButtonSize = \"24\" | \"32\" | \"40\" | \"52\" | \"72\";\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant of the icon button. @default \"primary\" */\n variant?: IconButtonVariant;\n /** Size of the button in pixels. @default \"40\" */\n size?: IconButtonSize;\n /** Icon element to render inside the button. */\n icon: React.ReactNode;\n /** When provided, displays a {@link Count} badge at the top-right corner (tertiary & navTray variants only). */\n counterValue?: number;\n}\n\n/**\n * A circular button containing only an icon. Use when an action can be\n * represented by an icon alone (e.g. close, send, mic). Pair with an\n * `aria-label` for accessibility.\n *\n * @example\n * ```tsx\n * <IconButton icon={<CloseIcon />} aria-label=\"Close\" variant=\"tertiary\" />\n * ```\n */\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n (\n { className, variant = \"primary\", size = \"40\", icon, counterValue, disabled = false, ...props },\n ref,\n ) => {\n if (process.env.NODE_ENV !== \"production\") {\n if (!props[\"aria-label\"] && !props[\"aria-labelledby\"] && !props.title) {\n console.warn(\n \"IconButton: No accessible name provided. Add an `aria-label`, `aria-labelledby`, or `title` prop so screen readers can announce this button.\",\n );\n }\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-testid=\"icon-button\"\n disabled={disabled}\n className={cn(\n // Base styles\n \"relative inline-flex shrink-0 items-center justify-center focus-visible:outline-none\",\n \"cursor-pointer rounded-full transition-all duration-150 ease-in-out disabled:cursor-default\",\n // Size variants\n sizeVariants[size],\n // Variant styles\n iconButtonVariants[variant],\n // Manual CSS overrides\n className,\n )}\n {...props}\n >\n <span\n className={cn(\"flex shrink-0 items-center justify-center\", iconSizeVariants[size])}\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n\n {counterValue !== undefined && (\n <Count\n value={counterValue}\n variant=\"alert\"\n size={countSizeMap[size]}\n className=\"absolute -top-0.5 -right-0.5\"\n />\n )}\n </button>\n );\n },\n);\n\nIconButton.displayName = \"IconButton\";\n"],"names":["React","jsxs","cn","jsx","Count"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,qBAAqB;AAAA,EACzB,SACE;AAAA,EACF,WACE;AAAA,EACF,UACE;AAAA,EACF,OACE;AAAA,EACF,UACE;AAAA,EACF,WACE;AAAA,EACF,SACE;AAAA,EACF,qBACE;AAAA,EACF,MAAM;AAAA,EACN,YACE;AACJ;AAEA,MAAM,mBAAmB;AAAA,EACvB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAAe;AAAA,EACnB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAA0C;AAAA,EAC9C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAuCO,MAAM,aAAaA,iBAAM;AAAA,EAC9B,CACE,EAAE,WAAW,UAAU,WAAW,OAAO,MAAM,MAAM,cAAc,WAAW,OAAO,GAAG,MAAA,GACxF,QACG;AACH,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,UAAI,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,MAAM,OAAO;AACrE,gBAAQ;AAAA,UACN;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAEA,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,eAAY;AAAA,QACZ;AAAA,QACA,WAAWC,GAAAA;AAAAA;AAAAA,UAET;AAAA,UACA;AAAA;AAAA,UAEA,aAAa,IAAI;AAAA;AAAA,UAEjB,mBAAmB,OAAO;AAAA;AAAA,UAE1B;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAAC,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWD,GAAAA,GAAG,6CAA6C,iBAAiB,IAAI,CAAC;AAAA,cACjF,eAAY;AAAA,cAEX,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGF,iBAAiB,UAChBC,2BAAAA;AAAAA,YAACC,MAAAA;AAAAA,YAAA;AAAA,cACC,OAAO;AAAA,cACP,SAAQ;AAAA,cACR,MAAM,aAAa,IAAI;AAAA,cACvB,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACZ;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,WAAW,cAAc;;"}
|