@alfadocs/ui-kit-debug 0.15.1 → 0.17.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.
Files changed (55) hide show
  1. package/dist/_chunks/benefit-card-DXmrAyfn.js +219 -0
  2. package/dist/_chunks/benefit-card-DXmrAyfn.js.map +1 -0
  3. package/dist/_chunks/copy-field-BCHAZ8QV.js +298 -0
  4. package/dist/_chunks/copy-field-BCHAZ8QV.js.map +1 -0
  5. package/dist/_chunks/{navigation-menu-Bav1d_wA.js → navigation-menu-DdufF-_4.js} +18 -18
  6. package/dist/_chunks/{navigation-menu-Bav1d_wA.js.map → navigation-menu-DdufF-_4.js.map} +1 -1
  7. package/dist/_chunks/{pagination-OQBlnb1H.js → pagination-F1ei4khE.js} +180 -158
  8. package/dist/_chunks/pagination-F1ei4khE.js.map +1 -0
  9. package/dist/_chunks/public-header.agent-sDi9N9su.js +562 -0
  10. package/dist/_chunks/public-header.agent-sDi9N9su.js.map +1 -0
  11. package/dist/agent-catalog.json +51 -1
  12. package/dist/components/benefit-card/benefit-card.d.ts +35 -0
  13. package/dist/components/benefit-card/benefit-card.d.ts.map +1 -0
  14. package/dist/components/benefit-card/index.d.ts +3 -0
  15. package/dist/components/benefit-card/index.d.ts.map +1 -0
  16. package/dist/components/benefit-card/index.js +5 -0
  17. package/dist/components/benefit-card/index.js.map +1 -0
  18. package/dist/components/card/card.d.ts +1 -1
  19. package/dist/components/copy-field/copy-field.agent.d.ts +16 -0
  20. package/dist/components/copy-field/copy-field.agent.d.ts.map +1 -0
  21. package/dist/components/copy-field/copy-field.d.ts +50 -0
  22. package/dist/components/copy-field/copy-field.d.ts.map +1 -0
  23. package/dist/components/copy-field/index.d.ts +5 -0
  24. package/dist/components/copy-field/index.d.ts.map +1 -0
  25. package/dist/components/copy-field/index.js +6 -0
  26. package/dist/components/copy-field/index.js.map +1 -0
  27. package/dist/components/index.d.ts +2 -0
  28. package/dist/components/index.d.ts.map +1 -1
  29. package/dist/components/navigation-menu/index.js +1 -1
  30. package/dist/components/pagination/index.js +1 -1
  31. package/dist/components/pagination/pagination.d.ts.map +1 -1
  32. package/dist/components/public-header/index.d.ts +1 -1
  33. package/dist/components/public-header/index.d.ts.map +1 -1
  34. package/dist/components/public-header/index.js +1 -1
  35. package/dist/components/public-header/public-header.d.ts +36 -1
  36. package/dist/components/public-header/public-header.d.ts.map +1 -1
  37. package/dist/components/stat/stat.d.ts +1 -1
  38. package/dist/hooks/use-controllable-state.d.ts +10 -0
  39. package/dist/hooks/use-controllable-state.d.ts.map +1 -0
  40. package/dist/hooks/use-copy-to-clipboard.d.ts +45 -0
  41. package/dist/hooks/use-copy-to-clipboard.d.ts.map +1 -0
  42. package/dist/i18n/config.js +21 -0
  43. package/dist/i18n/config.js.map +1 -1
  44. package/dist/i18n/resources.d.ts +21 -0
  45. package/dist/i18n/resources.d.ts.map +1 -1
  46. package/dist/index.js +458 -453
  47. package/dist/index.js.map +1 -1
  48. package/dist/locales/de.json +7 -0
  49. package/dist/locales/en.json +7 -0
  50. package/dist/locales/it.json +7 -0
  51. package/dist/tokens.css +1 -1
  52. package/package.json +9 -1
  53. package/dist/_chunks/pagination-OQBlnb1H.js.map +0 -1
  54. package/dist/_chunks/public-header.agent-ZLBAQ30j.js +0 -242
  55. package/dist/_chunks/public-header.agent-ZLBAQ30j.js.map +0 -1
@@ -0,0 +1,219 @@
1
+ import { jsxs as v, jsx as r } from "react/jsx-runtime";
2
+ import { forwardRef as _, useContext as w, Children as k, createContext as y } from "react";
3
+ import { c as s } from "./index-D2ZczOXr.js";
4
+ const b = [
5
+ "violet",
6
+ "purple",
7
+ "magenta",
8
+ "blue",
9
+ "green",
10
+ "red"
11
+ ], m = y(null), C = s("ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-lg)]", {
12
+ variants: {
13
+ columns: {
14
+ 1: "ds:md:grid-cols-1",
15
+ 2: "ds:md:grid-cols-2",
16
+ 3: "ds:md:grid-cols-3",
17
+ 4: "ds:md:grid-cols-4"
18
+ }
19
+ },
20
+ defaultVariants: { columns: 3 }
21
+ }), N = s(
22
+ [
23
+ "ds:relative ds:rounded-[var(--radius-lg)] ds:overflow-hidden",
24
+ "ds:flex ds:flex-col ds:h-full",
25
+ "ds:bg-[var(--card)] ds:text-[var(--card-foreground)]",
26
+ // Hover lift — the transform is gated through `motion-safe:` so users
27
+ // with `prefers-reduced-motion: reduce` see only the shadow change.
28
+ // `--animation-duration` is pinned to 0ms in the accessible theme,
29
+ // which collapses the transition without dropping the rule entirely.
30
+ "ds:transition-[transform,box-shadow] ds:duration-[var(--animation-duration)]",
31
+ "ds:motion-reduce:transition-none",
32
+ "ds:motion-safe:hover:-translate-y-1"
33
+ ].join(" "),
34
+ {
35
+ variants: {
36
+ variant: {
37
+ elevated: "ds:shadow-[var(--shadow-card)]",
38
+ outlined: "ds:border ds:border-[color:var(--card-border)]"
39
+ }
40
+ },
41
+ defaultVariants: { variant: "elevated" }
42
+ }
43
+ ), V = s(
44
+ "ds:absolute ds:inset-inline-0 ds:top-0 ds:h-[4px] ds:pointer-events-none",
45
+ {
46
+ variants: {
47
+ accent: {
48
+ primary: "ds:bg-linear-to-r ds:from-[var(--primary)] ds:to-[var(--accent)]",
49
+ accent: "ds:bg-linear-to-r ds:from-[var(--accent)] ds:to-[var(--primary)]",
50
+ info: "ds:bg-linear-to-r ds:from-[var(--info)] ds:to-[var(--info)]",
51
+ success: "ds:bg-linear-to-r ds:from-[var(--success)] ds:to-[var(--success)]",
52
+ warning: "ds:bg-linear-to-r ds:from-[var(--warning)] ds:to-[var(--warning)]",
53
+ violet: "ds:bg-linear-to-r ds:from-[var(--color-violet-500)] ds:to-[var(--color-purple-500)]",
54
+ purple: "ds:bg-linear-to-r ds:from-[var(--color-purple-500)] ds:to-[var(--color-magenta-500)]",
55
+ magenta: "ds:bg-linear-to-r ds:from-[var(--color-magenta-500)] ds:to-[var(--color-violet-500)]",
56
+ blue: "ds:bg-linear-to-r ds:from-[var(--color-blue-500)] ds:to-[var(--color-green-500)]",
57
+ green: "ds:bg-linear-to-r ds:from-[var(--color-green-500)] ds:to-[var(--color-red-500)]",
58
+ red: "ds:bg-linear-to-r ds:from-[var(--color-red-500)] ds:to-[var(--color-blue-500)]"
59
+ }
60
+ },
61
+ defaultVariants: { accent: "primary" }
62
+ }
63
+ ), j = s("", {
64
+ variants: {
65
+ accent: {
66
+ primary: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--primary)_18%,transparent)]",
67
+ accent: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--accent)_18%,transparent)]",
68
+ info: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--info)_18%,transparent)]",
69
+ success: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--success)_18%,transparent)]",
70
+ warning: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--warning)_18%,transparent)]",
71
+ violet: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-violet-500)_18%,transparent)]",
72
+ purple: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-purple-500)_18%,transparent)]",
73
+ magenta: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-magenta-500)_18%,transparent)]",
74
+ blue: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-blue-500)_18%,transparent)]",
75
+ green: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-green-500)_18%,transparent)]",
76
+ red: "ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-red-500)_18%,transparent)]"
77
+ }
78
+ },
79
+ defaultVariants: { accent: "primary" }
80
+ }), B = s(
81
+ [
82
+ "ds:inline-flex ds:items-center ds:justify-center",
83
+ "ds:size-14 ds:rounded-[var(--radius-md)] ds:shrink-0",
84
+ "ds:[&>svg]:size-7",
85
+ "ds:shadow-[inset_0_1px_0_color-mix(in_srgb,white_40%,transparent)]"
86
+ ].join(" "),
87
+ {
88
+ variants: {
89
+ accent: {
90
+ primary: "ds:text-[color:var(--primary)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--primary)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--accent)_8%,var(--background))]",
91
+ accent: "ds:text-[color:var(--accent)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--accent)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--primary)_8%,var(--background))]",
92
+ info: "ds:text-[color:var(--info)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--info)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--info)_8%,var(--background))]",
93
+ success: "ds:text-[color:var(--success)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--success)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--success)_8%,var(--background))]",
94
+ warning: "ds:text-[color:var(--warning)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--warning)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--warning)_8%,var(--background))]",
95
+ violet: "ds:text-[color:var(--color-violet-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-violet-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-purple-500)_8%,var(--background))]",
96
+ purple: "ds:text-[color:var(--color-purple-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-purple-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-magenta-500)_8%,var(--background))]",
97
+ magenta: "ds:text-[color:var(--color-magenta-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-magenta-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-violet-500)_8%,var(--background))]",
98
+ blue: "ds:text-[color:var(--color-blue-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-blue-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-green-500)_8%,var(--background))]",
99
+ green: "ds:text-[color:var(--color-green-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-green-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-red-500)_8%,var(--background))]",
100
+ red: "ds:text-[color:var(--color-red-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-red-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-blue-500)_8%,var(--background))]"
101
+ }
102
+ },
103
+ defaultVariants: { accent: "primary" }
104
+ }
105
+ ), R = s(
106
+ [
107
+ "type-eyebrow",
108
+ "ds:rounded-[var(--radius-full)]",
109
+ "ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)]"
110
+ ].join(" "),
111
+ {
112
+ variants: {
113
+ accent: {
114
+ primary: "ds:text-[color:var(--color-violet-700)] ds:bg-[color-mix(in_srgb,var(--primary)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--primary)_30%,transparent)]",
115
+ accent: "ds:text-[color:var(--color-magenta-700)] ds:bg-[color-mix(in_srgb,var(--accent)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--accent)_30%,transparent)]",
116
+ info: "ds:text-[color:var(--color-blue-700)] ds:bg-[color-mix(in_srgb,var(--info)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--info)_30%,transparent)]",
117
+ success: "ds:text-[color:var(--color-green-700)] ds:bg-[color-mix(in_srgb,var(--success)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--success)_30%,transparent)]",
118
+ warning: "ds:text-[color:var(--color-red-700)] ds:bg-[color-mix(in_srgb,var(--warning)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--warning)_30%,transparent)]",
119
+ violet: "ds:text-[color:var(--color-violet-700)] ds:bg-[color-mix(in_srgb,var(--color-violet-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-violet-500)_30%,transparent)]",
120
+ purple: "ds:text-[color:var(--color-purple-700)] ds:bg-[color-mix(in_srgb,var(--color-purple-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-purple-500)_30%,transparent)]",
121
+ magenta: "ds:text-[color:var(--color-magenta-700)] ds:bg-[color-mix(in_srgb,var(--color-magenta-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-magenta-500)_30%,transparent)]",
122
+ blue: "ds:text-[color:var(--color-blue-700)] ds:bg-[color-mix(in_srgb,var(--color-blue-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-blue-500)_30%,transparent)]",
123
+ green: "ds:text-[color:var(--color-green-700)] ds:bg-[color-mix(in_srgb,var(--color-green-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-green-500)_30%,transparent)]",
124
+ red: "ds:text-[color:var(--color-red-700)] ds:bg-[color-mix(in_srgb,var(--color-red-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-red-500)_30%,transparent)]"
125
+ }
126
+ },
127
+ defaultVariants: { accent: "primary" }
128
+ }
129
+ );
130
+ function S(a, o) {
131
+ return a !== "auto" ? a : o ? b[o.index % b.length] : "primary";
132
+ }
133
+ const p = _(
134
+ ({ columns: a = 3, children: o, className: i, ...n }, c) => {
135
+ const l = k.toArray(o);
136
+ return /* @__PURE__ */ r(
137
+ "div",
138
+ {
139
+ ref: c,
140
+ "data-component": "benefit-card-row",
141
+ className: C({ columns: a, className: i }),
142
+ ...n,
143
+ children: l.map((d, t) => /* @__PURE__ */ r(m.Provider, { value: { index: t }, children: d }, t))
144
+ }
145
+ );
146
+ }
147
+ );
148
+ p.displayName = "BenefitCard.Row";
149
+ const x = _(
150
+ ({
151
+ step: a,
152
+ icon: o,
153
+ title: i,
154
+ cta: n,
155
+ variant: c = "elevated",
156
+ accent: l = "auto",
157
+ children: d,
158
+ className: t,
159
+ ...u
160
+ }, f) => {
161
+ const h = w(m), e = S(l, h), g = typeof a == "number";
162
+ return /* @__PURE__ */ v(
163
+ "article",
164
+ {
165
+ ref: f,
166
+ "data-component": "benefit-card",
167
+ "data-accent": e,
168
+ className: [
169
+ N({ variant: c }),
170
+ j({ accent: e }),
171
+ t
172
+ ].filter(Boolean).join(" "),
173
+ ...u,
174
+ children: [
175
+ /* @__PURE__ */ r(
176
+ "span",
177
+ {
178
+ "aria-hidden": "true",
179
+ "data-part": "accent-strip",
180
+ className: V({ accent: e })
181
+ }
182
+ ),
183
+ /* @__PURE__ */ v("div", { className: "ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-lg)] ds:flex-1", children: [
184
+ (o || g) && /* @__PURE__ */ v("div", { className: "ds:flex ds:items-start ds:justify-between ds:gap-[var(--spacing-sm)]", children: [
185
+ o ? /* @__PURE__ */ r(
186
+ "span",
187
+ {
188
+ "aria-hidden": "true",
189
+ className: B({ accent: e }),
190
+ children: o
191
+ }
192
+ ) : /* @__PURE__ */ r("span", { "aria-hidden": "true" }),
193
+ g ? /* @__PURE__ */ r(
194
+ "span",
195
+ {
196
+ "aria-hidden": "true",
197
+ "data-part": "step",
198
+ className: R({ accent: e }),
199
+ children: String(a).padStart(2, "0")
200
+ }
201
+ ) : null
202
+ ] }),
203
+ /* @__PURE__ */ r("h3", { className: "type-title-card ds:text-[var(--foreground)]", children: i }),
204
+ d ? /* @__PURE__ */ r("div", { className: "type-body ds:text-[var(--muted-foreground)] ds:flex-1", children: d }) : null,
205
+ n ? /* @__PURE__ */ r("div", { className: "ds:mt-[var(--spacing-xs)]", children: n }) : null
206
+ ] })
207
+ ]
208
+ }
209
+ );
210
+ }
211
+ );
212
+ x.displayName = "BenefitCard";
213
+ const H = Object.assign(x, {
214
+ Row: p
215
+ });
216
+ export {
217
+ H as B
218
+ };
219
+ //# sourceMappingURL=benefit-card-DXmrAyfn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benefit-card-DXmrAyfn.js","sources":["../../src/components/benefit-card/benefit-card.tsx"],"sourcesContent":["/* ------------------------------------------------------------------ */\n/* BenefitCard — marketing-surface card for \"benefit row\" / \"how it */\n/* works\" / \"why choose us\" sections. */\n/* */\n/* Visually distinguished from <Card> by: */\n/* 1. A 4px accent strip across the top (logical block-start). */\n/* 2. A tinted icon chip inside the body using `color-mix(in srgb, */\n/* var(--accent-token) 12%, var(--background))`. */\n/* 3. An optional zero-padded step chip (\"01\", \"02\", ...) in the */\n/* top-end corner. */\n/* 4. A hover lift (translateY -2px + --shadow-hover), gated through */\n/* `--animation-duration` so the accessible theme freezes it. */\n/* */\n/* Compound API: */\n/* <BenefitCard.Row columns={3}> */\n/* <BenefitCard step={1} icon={…} title=\"…\">…</BenefitCard> */\n/* ... */\n/* </BenefitCard.Row> */\n/* */\n/* `accent=\"auto\"` rotates through the brand palette by row index */\n/* (violet → purple → magenta → blue → green → red, then wraps). */\n/* Outside a Row, `auto` falls back to `primary`. */\n/* ------------------------------------------------------------------ */\n\nimport {\n Children,\n createContext,\n forwardRef,\n useContext,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\n\n/* ------------------------------------------------------------------ */\n/* Accent wheel — used by `accent=\"auto\"` inside a Row. */\n/* ------------------------------------------------------------------ */\n\nconst ACCENT_WHEEL = [\n 'violet',\n 'purple',\n 'magenta',\n 'blue',\n 'green',\n 'red',\n] as const;\n\ntype WheelAccent = (typeof ACCENT_WHEEL)[number];\ntype SemanticAccent = 'primary' | 'accent' | 'info' | 'success' | 'warning';\ntype ResolvedAccent = SemanticAccent | WheelAccent;\ntype AccentProp = SemanticAccent | WheelAccent | 'auto';\n\n/* ------------------------------------------------------------------ */\n/* Row context */\n/* ------------------------------------------------------------------ */\n\ninterface RowContextValue {\n index: number;\n}\n\nconst RowContext = createContext<RowContextValue | null>(null);\n\n/* ------------------------------------------------------------------ */\n/* CVA — Row grid */\n/* ------------------------------------------------------------------ */\n\nconst rowVariants = cva('ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-lg)]', {\n variants: {\n columns: {\n 1: 'ds:md:grid-cols-1',\n 2: 'ds:md:grid-cols-2',\n 3: 'ds:md:grid-cols-3',\n 4: 'ds:md:grid-cols-4',\n },\n },\n defaultVariants: { columns: 3 },\n});\n\n/* ------------------------------------------------------------------ */\n/* CVA — BenefitCard root */\n/* */\n/* The top 4px accent strip uses `border-block-start` (logical) so it */\n/* sits at the inline-start-block-start corner regardless of writing */\n/* direction. Border colour is set per-accent in the `accent` variant. */\n/* ------------------------------------------------------------------ */\n\n// Card chrome — no per-accent variant; the gradient top strip is rendered\n// as a separate sibling element so it can use a linear-gradient. The\n// hover shadow's tint comes from `hoverShadowVariants` on the same root.\nconst cardVariants = cva(\n [\n 'ds:relative ds:rounded-[var(--radius-lg)] ds:overflow-hidden',\n 'ds:flex ds:flex-col ds:h-full',\n 'ds:bg-[var(--card)] ds:text-[var(--card-foreground)]',\n // Hover lift — the transform is gated through `motion-safe:` so users\n // with `prefers-reduced-motion: reduce` see only the shadow change.\n // `--animation-duration` is pinned to 0ms in the accessible theme,\n // which collapses the transition without dropping the rule entirely.\n 'ds:transition-[transform,box-shadow] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:motion-safe:hover:-translate-y-1',\n ].join(' '),\n {\n variants: {\n variant: {\n elevated: 'ds:shadow-[var(--shadow-card)]',\n outlined: 'ds:border ds:border-[color:var(--card-border)]',\n },\n },\n defaultVariants: { variant: 'elevated' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Gradient top strip — Treatment B (Vivid). */\n/* */\n/* The strip is an absolutely-positioned `<span>` so its background can */\n/* be a `linear-gradient`. For brand-wheel accents (violet → purple → */\n/* magenta → blue → green → red) the gradient pairs with the next */\n/* wheel token. For semantic accents the gradient is a solid pair */\n/* (start=end) — same visual weight, less colour drama. */\n/* ------------------------------------------------------------------ */\n\nconst topStripVariants = cva(\n 'ds:absolute ds:inset-inline-0 ds:top-0 ds:h-[4px] ds:pointer-events-none',\n {\n variants: {\n accent: {\n primary:\n 'ds:bg-linear-to-r ds:from-[var(--primary)] ds:to-[var(--accent)]',\n accent:\n 'ds:bg-linear-to-r ds:from-[var(--accent)] ds:to-[var(--primary)]',\n info: 'ds:bg-linear-to-r ds:from-[var(--info)] ds:to-[var(--info)]',\n success:\n 'ds:bg-linear-to-r ds:from-[var(--success)] ds:to-[var(--success)]',\n warning:\n 'ds:bg-linear-to-r ds:from-[var(--warning)] ds:to-[var(--warning)]',\n violet:\n 'ds:bg-linear-to-r ds:from-[var(--color-violet-500)] ds:to-[var(--color-purple-500)]',\n purple:\n 'ds:bg-linear-to-r ds:from-[var(--color-purple-500)] ds:to-[var(--color-magenta-500)]',\n magenta:\n 'ds:bg-linear-to-r ds:from-[var(--color-magenta-500)] ds:to-[var(--color-violet-500)]',\n blue: 'ds:bg-linear-to-r ds:from-[var(--color-blue-500)] ds:to-[var(--color-green-500)]',\n green:\n 'ds:bg-linear-to-r ds:from-[var(--color-green-500)] ds:to-[var(--color-red-500)]',\n red: 'ds:bg-linear-to-r ds:from-[var(--color-red-500)] ds:to-[var(--color-blue-500)]',\n },\n },\n defaultVariants: { accent: 'primary' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Hover shadow — coloured halo on hover, tinted by accent. */\n/* ------------------------------------------------------------------ */\n\nconst hoverShadowVariants = cva('', {\n variants: {\n accent: {\n primary:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--primary)_18%,transparent)]',\n accent:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--accent)_18%,transparent)]',\n info: 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--info)_18%,transparent)]',\n success:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--success)_18%,transparent)]',\n warning:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--warning)_18%,transparent)]',\n violet:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-violet-500)_18%,transparent)]',\n purple:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-purple-500)_18%,transparent)]',\n magenta:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-magenta-500)_18%,transparent)]',\n blue: 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-blue-500)_18%,transparent)]',\n green:\n 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-green-500)_18%,transparent)]',\n red: 'ds:hover:shadow-[0_20px_40px_color-mix(in_srgb,var(--color-red-500)_18%,transparent)]',\n },\n },\n defaultVariants: { accent: 'primary' },\n});\n\n/* ------------------------------------------------------------------ */\n/* CVA — icon chip */\n/* */\n/* The chip background uses `color-mix(in srgb, <token> 12%, */\n/* var(--background))` so it stays legible across themes. The Tailwind */\n/* JIT requires underscores in arbitrary-value classes wherever */\n/* whitespace would otherwise terminate the class. */\n/* ------------------------------------------------------------------ */\n\n// Icon chip — gradient tint (Treatment B). The chip pairs the resolved\n// accent with the \"next\" wheel/semantic token so the bg reads as a soft\n// diagonal blend instead of a flat tint, picking up the energy of the\n// gradient top strip. An inset highlight (`inset 0 1px 0` half-white)\n// adds a subtle glass edge.\nconst iconChipVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:size-14 ds:rounded-[var(--radius-md)] ds:shrink-0',\n 'ds:[&>svg]:size-7',\n 'ds:shadow-[inset_0_1px_0_color-mix(in_srgb,white_40%,transparent)]',\n ].join(' '),\n {\n variants: {\n accent: {\n primary:\n 'ds:text-[color:var(--primary)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--primary)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--accent)_8%,var(--background))]',\n accent:\n 'ds:text-[color:var(--accent)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--accent)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--primary)_8%,var(--background))]',\n info: 'ds:text-[color:var(--info)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--info)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--info)_8%,var(--background))]',\n success:\n 'ds:text-[color:var(--success)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--success)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--success)_8%,var(--background))]',\n warning:\n 'ds:text-[color:var(--warning)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--warning)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--warning)_8%,var(--background))]',\n violet:\n 'ds:text-[color:var(--color-violet-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-violet-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-purple-500)_8%,var(--background))]',\n purple:\n 'ds:text-[color:var(--color-purple-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-purple-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-magenta-500)_8%,var(--background))]',\n magenta:\n 'ds:text-[color:var(--color-magenta-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-magenta-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-violet-500)_8%,var(--background))]',\n blue: 'ds:text-[color:var(--color-blue-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-blue-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-green-500)_8%,var(--background))]',\n green:\n 'ds:text-[color:var(--color-green-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-green-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-red-500)_8%,var(--background))]',\n red: 'ds:text-[color:var(--color-red-500)] ds:bg-linear-to-br ds:from-[color-mix(in_srgb,var(--color-red-500)_22%,var(--background))] ds:to-[color-mix(in_srgb,var(--color-blue-500)_8%,var(--background))]',\n },\n },\n defaultVariants: { accent: 'primary' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Step chip — brand-tinted with a thin matching border. */\n/* ------------------------------------------------------------------ */\n\n// Text colour uses the -700 ramp step rather than -500 so the chip's\n// small `01` label clears WCAG AA (≥4.5:1) against its 12 %-tinted bg.\n// The brand -500 fails on the tinted surface (~4.07:1). For the\n// semantic accents we pin to the same brand-700 the kit resolves them\n// to (primary→violet-700, accent→magenta-700, etc.) so each variant\n// reads AA in light theme. In dark theme the tokens auto-invert and\n// the dark-bg-against-light-tint relationship stays comfortably AA.\nconst stepChipVariants = cva(\n [\n 'type-eyebrow',\n 'ds:rounded-[var(--radius-full)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)]',\n ].join(' '),\n {\n variants: {\n accent: {\n primary:\n 'ds:text-[color:var(--color-violet-700)] ds:bg-[color-mix(in_srgb,var(--primary)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--primary)_30%,transparent)]',\n accent:\n 'ds:text-[color:var(--color-magenta-700)] ds:bg-[color-mix(in_srgb,var(--accent)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--accent)_30%,transparent)]',\n info: 'ds:text-[color:var(--color-blue-700)] ds:bg-[color-mix(in_srgb,var(--info)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--info)_30%,transparent)]',\n success:\n 'ds:text-[color:var(--color-green-700)] ds:bg-[color-mix(in_srgb,var(--success)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--success)_30%,transparent)]',\n warning:\n 'ds:text-[color:var(--color-red-700)] ds:bg-[color-mix(in_srgb,var(--warning)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--warning)_30%,transparent)]',\n violet:\n 'ds:text-[color:var(--color-violet-700)] ds:bg-[color-mix(in_srgb,var(--color-violet-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-violet-500)_30%,transparent)]',\n purple:\n 'ds:text-[color:var(--color-purple-700)] ds:bg-[color-mix(in_srgb,var(--color-purple-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-purple-500)_30%,transparent)]',\n magenta:\n 'ds:text-[color:var(--color-magenta-700)] ds:bg-[color-mix(in_srgb,var(--color-magenta-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-magenta-500)_30%,transparent)]',\n blue: 'ds:text-[color:var(--color-blue-700)] ds:bg-[color-mix(in_srgb,var(--color-blue-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-blue-500)_30%,transparent)]',\n green:\n 'ds:text-[color:var(--color-green-700)] ds:bg-[color-mix(in_srgb,var(--color-green-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-green-500)_30%,transparent)]',\n red: 'ds:text-[color:var(--color-red-700)] ds:bg-[color-mix(in_srgb,var(--color-red-500)_12%,var(--background))] ds:[border:1px_solid_color-mix(in_srgb,var(--color-red-500)_30%,transparent)]',\n },\n },\n defaultVariants: { accent: 'primary' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface BenefitCardProps extends Omit<\n HTMLAttributes<HTMLElement>,\n 'title'\n> {\n /** Step number; rendered as a zero-padded chip (\"01\", \"02\", …). Omit to hide. */\n step?: number;\n /** Icon node — usually an `<svg>` 24-32px. Rendered inside a tinted square chip. */\n icon?: ReactNode;\n /** Card heading. Always rendered inside an `<h3>` — pass only inline / phrasing content. */\n title: ReactNode;\n /** Optional CTA — usually a `<Button intent=\"link\">` or kit `<Link>`. Rendered at the block-end. */\n cta?: ReactNode;\n /** Surface treatment. */\n variant?: 'elevated' | 'outlined';\n /**\n * Accent colour. `auto` (default inside a `<BenefitCard.Row>`) rotates through the brand\n * palette by row index: violet → purple → magenta → blue → green → red, then wraps.\n * Outside a Row, `auto` falls back to `primary`.\n */\n accent?: AccentProp;\n /** Body content (description / list / inline copy). */\n children?: ReactNode;\n}\n\nexport interface BenefitCardRowProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'children'\n> {\n /** Number of columns at md+; defaults to 3. Collapses to 1 at < md. */\n columns?: 1 | 2 | 3 | 4;\n children?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Accent resolution */\n/* ------------------------------------------------------------------ */\n\nfunction resolveAccent(\n accent: AccentProp,\n rowCtx: RowContextValue | null,\n): ResolvedAccent {\n if (accent !== 'auto') return accent;\n if (rowCtx) return ACCENT_WHEEL[rowCtx.index % ACCENT_WHEEL.length];\n return 'primary';\n}\n\n/* ------------------------------------------------------------------ */\n/* Row */\n/* */\n/* Wraps every child in a `RowContext.Provider` so the child can look */\n/* up its index and pick a wheel colour when `accent=\"auto\"`. */\n/* ------------------------------------------------------------------ */\n\nconst BenefitCardRow = forwardRef<HTMLDivElement, BenefitCardRowProps>(\n ({ columns = 3, children, className, ...rest }, ref) => {\n const items = Children.toArray(children);\n return (\n <div\n ref={ref}\n data-component=\"benefit-card-row\"\n className={rowVariants({ columns, className })}\n {...rest}\n >\n {items.map((child, index) => (\n <RowContext.Provider key={index} value={{ index }}>\n {child}\n </RowContext.Provider>\n ))}\n </div>\n );\n },\n);\nBenefitCardRow.displayName = 'BenefitCard.Row';\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nconst BenefitCardRoot = forwardRef<HTMLElement, BenefitCardProps>(\n (\n {\n step,\n icon,\n title,\n cta,\n variant = 'elevated',\n accent = 'auto',\n children,\n className,\n ...rest\n },\n ref,\n ) => {\n const rowCtx = useContext(RowContext);\n const resolved = resolveAccent(accent, rowCtx);\n const hasStep = typeof step === 'number';\n\n return (\n <article\n ref={ref}\n data-component=\"benefit-card\"\n data-accent={resolved}\n className={[\n cardVariants({ variant }),\n hoverShadowVariants({ accent: resolved }),\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {/* Gradient top strip — Treatment B visual signature. Sits above\n the card body via absolute positioning. */}\n <span\n aria-hidden=\"true\"\n data-part=\"accent-strip\"\n className={topStripVariants({ accent: resolved })}\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-lg)] ds:flex-1\">\n {(icon || hasStep) && (\n <div className=\"ds:flex ds:items-start ds:justify-between ds:gap-[var(--spacing-sm)]\">\n {icon ? (\n <span\n aria-hidden=\"true\"\n className={iconChipVariants({ accent: resolved })}\n >\n {icon}\n </span>\n ) : (\n <span aria-hidden=\"true\" />\n )}\n {hasStep ? (\n <span\n aria-hidden=\"true\"\n data-part=\"step\"\n className={stepChipVariants({ accent: resolved })}\n >\n {String(step).padStart(2, '0')}\n </span>\n ) : null}\n </div>\n )}\n <h3 className=\"type-title-card ds:text-[var(--foreground)]\">\n {title}\n </h3>\n {children ? (\n <div className=\"type-body ds:text-[var(--muted-foreground)] ds:flex-1\">\n {children}\n </div>\n ) : null}\n {cta ? <div className=\"ds:mt-[var(--spacing-xs)]\">{cta}</div> : null}\n </div>\n </article>\n );\n },\n);\nBenefitCardRoot.displayName = 'BenefitCard';\n\n/* ------------------------------------------------------------------ */\n/* Compound export */\n/* ------------------------------------------------------------------ */\n\nexport const BenefitCard = Object.assign(BenefitCardRoot, {\n Row: BenefitCardRow,\n});\n"],"names":["ACCENT_WHEEL","RowContext","createContext","rowVariants","cva","cardVariants","topStripVariants","hoverShadowVariants","iconChipVariants","stepChipVariants","resolveAccent","accent","rowCtx","BenefitCardRow","forwardRef","columns","children","className","rest","ref","items","Children","jsx","child","index","BenefitCardRoot","step","icon","title","cta","variant","useContext","resolved","hasStep","jsxs","BenefitCard"],"mappings":"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"}
@@ -0,0 +1,298 @@
1
+ import { jsxs as P, jsx as p } from "react/jsx-runtime";
2
+ import { useRef as m, useEffect as V, useState as A, useCallback as y, forwardRef as _, useMemo as H } from "react";
3
+ import { c as x } from "./index-D2ZczOXr.js";
4
+ import { useTranslation as O } from "react-i18next";
5
+ import { B as W } from "./button-DD_0Xdmr.js";
6
+ import { u as q } from "./registry-C9nwlNyL.js";
7
+ import { C as D } from "./check-DPdL_Sm7.js";
8
+ import { C as G } from "./copy-B00HK7tj.js";
9
+ const J = typeof navigator < "u" && typeof navigator.clipboard < "u" && typeof navigator.clipboard.writeText == "function";
10
+ function Q(t = {}) {
11
+ const { resetAfterMs: e = 2e3, writer: s } = t, o = m(s);
12
+ V(() => {
13
+ o.current = s;
14
+ }, [s]);
15
+ const [C, i] = A("idle"), [T, u] = A(null), n = m(null), a = y(() => {
16
+ n.current !== null && (clearTimeout(n.current), n.current = null);
17
+ }, []), d = y(() => {
18
+ a(), i("idle"), u(null);
19
+ }, [a]), z = y(
20
+ async (c) => {
21
+ a();
22
+ const h = o.current;
23
+ let l = !1;
24
+ if (h)
25
+ try {
26
+ l = await h(c);
27
+ } catch {
28
+ l = !1;
29
+ }
30
+ else {
31
+ if (!(J || typeof navigator < "u" && typeof navigator.clipboard < "u" && typeof navigator.clipboard.writeText == "function"))
32
+ return i("error"), u(null), !1;
33
+ try {
34
+ await navigator.clipboard.writeText(c), l = !0;
35
+ } catch {
36
+ l = !1;
37
+ }
38
+ }
39
+ return l ? (i("copied"), u(c), e > 0 && (n.current = setTimeout(() => {
40
+ n.current = null, i("idle");
41
+ }, e)), !0) : (i("error"), u(null), !1);
42
+ },
43
+ [a, e]
44
+ );
45
+ return V(() => a, [a]), { status: C, copiedValue: T, copy: z, reset: d };
46
+ }
47
+ const U = {
48
+ id: "copy-field",
49
+ capabilities: [],
50
+ state: {
51
+ value: {
52
+ type: "string",
53
+ descriptionKey: "ui.agent.copyField.state.value",
54
+ description: "The value displayed in the read-only field.",
55
+ read: (t) => t.getValue()
56
+ },
57
+ copied: {
58
+ type: "boolean",
59
+ descriptionKey: "ui.agent.copyField.state.copied",
60
+ description: "True for the brief window after a successful copy.",
61
+ read: (t) => t.isCopied()
62
+ }
63
+ },
64
+ actions: {
65
+ copy: {
66
+ safety: "write",
67
+ descriptionKey: "ui.agent.copyField.actions.copy",
68
+ description: "Programmatically trigger the clipboard write.",
69
+ invoke: (t) => t.copy()
70
+ }
71
+ },
72
+ domHooks: {
73
+ root: {
74
+ attr: "data-component",
75
+ value: "copy-field",
76
+ description: "Marks the CopyField root. The trailing button uses `aria-label` keyed off the copy / copied state."
77
+ },
78
+ instanceId: {
79
+ attr: "data-component-id",
80
+ sourceProp: "id",
81
+ description: "Sourced from the id prop, when provided."
82
+ }
83
+ }
84
+ };
85
+ async function X(t) {
86
+ var o;
87
+ if (typeof navigator < "u" && ((o = navigator.clipboard) != null && o.writeText))
88
+ try {
89
+ return await navigator.clipboard.writeText(t), !0;
90
+ } catch {
91
+ }
92
+ if (typeof document > "u") return !1;
93
+ const e = document.createElement("textarea");
94
+ e.value = t, e.setAttribute("readonly", ""), e.style.position = "absolute", e.style.setProperty("inset-inline-start", "-9999px"), document.body.appendChild(e), e.select();
95
+ let s = !1;
96
+ try {
97
+ s = document.execCommand("copy");
98
+ } catch {
99
+ s = !1;
100
+ }
101
+ return document.body.removeChild(e), s;
102
+ }
103
+ const Y = x(
104
+ [
105
+ "ds:inline-flex ds:items-stretch ds:w-full",
106
+ "ds:rounded-[var(--radius-sm)] ds:bg-input ds:text-foreground",
107
+ "ds:border ds:border-border",
108
+ "ds:shadow-[var(--shadow-input)]",
109
+ "ds:focus-within:outline-[length:var(--focus-ring-width)] ds:focus-within:outline-solid",
110
+ "ds:focus-within:outline-ring ds:focus-within:outline-offset-[length:var(--focus-ring-offset)]",
111
+ "ds:forced-colors:focus-within:outline-[CanvasText]",
112
+ "ds:transition-[colors,box-shadow] ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none",
113
+ "ds:overflow-hidden"
114
+ ].join(" "),
115
+ {
116
+ variants: {
117
+ size: {
118
+ sm: "ds:h-8 ds:text-[var(--font-size-sm)]",
119
+ md: "ds:h-[var(--min-target-size)] ds:text-[var(--font-size-base)]",
120
+ lg: "ds:h-12 ds:text-[var(--font-size-lg)]"
121
+ },
122
+ disabled: {
123
+ true: "ds:opacity-50 ds:cursor-not-allowed",
124
+ false: ""
125
+ }
126
+ },
127
+ defaultVariants: { size: "md", disabled: !1 }
128
+ }
129
+ ), Z = x(
130
+ [
131
+ "ds:flex-1 ds:min-w-0 ds:bg-transparent ds:border-0 ds:outline-none",
132
+ "ds:text-foreground",
133
+ "ds:disabled:cursor-not-allowed"
134
+ ].join(" "),
135
+ {
136
+ variants: {
137
+ intent: {
138
+ default: "",
139
+ // `--primary` is calibrated for foreground use (violet-500 light,
140
+ // magenta-500 dark) — both pass AA against their input backgrounds.
141
+ primary: "ds:text-primary ds:font-medium"
142
+ },
143
+ size: {
144
+ sm: "ds:text-[var(--font-size-sm)]",
145
+ md: "ds:text-[var(--font-size-base)]",
146
+ lg: "ds:text-[var(--font-size-lg)]"
147
+ },
148
+ wrap: {
149
+ true: "ds:[overflow-wrap:anywhere] ds:whitespace-normal",
150
+ false: "ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap"
151
+ },
152
+ hasStartIcon: {
153
+ true: "",
154
+ false: ""
155
+ }
156
+ },
157
+ // Explicit pairs decide the leading padding — single ps-* per cell, so
158
+ // there's no fight between size + hasStartIcon under Tailwind's flat
159
+ // utility precedence.
160
+ compoundVariants: [
161
+ { size: "sm", hasStartIcon: !1, class: "ds:ps-[var(--spacing-sm)]" },
162
+ { size: "md", hasStartIcon: !1, class: "ds:ps-[var(--spacing-sm)]" },
163
+ { size: "lg", hasStartIcon: !1, class: "ds:ps-[var(--spacing-md)]" },
164
+ { size: "sm", hasStartIcon: !0, class: "ds:ps-[var(--spacing-xs)]" },
165
+ { size: "md", hasStartIcon: !0, class: "ds:ps-[var(--spacing-xs)]" },
166
+ { size: "lg", hasStartIcon: !0, class: "ds:ps-[var(--spacing-sm)]" }
167
+ ],
168
+ defaultVariants: {
169
+ intent: "default",
170
+ size: "md",
171
+ wrap: !1,
172
+ hasStartIcon: !1
173
+ }
174
+ }
175
+ ), $ = x(
176
+ [
177
+ "ds:inline-flex ds:items-center ds:justify-center ds:shrink-0",
178
+ "ds:text-muted-foreground",
179
+ "ds:[&_svg]:size-4"
180
+ ].join(" "),
181
+ {
182
+ variants: {
183
+ size: {
184
+ sm: "ds:ps-[var(--spacing-sm)]",
185
+ md: "ds:ps-[var(--spacing-sm)]",
186
+ lg: "ds:ps-[var(--spacing-md)]"
187
+ }
188
+ },
189
+ defaultVariants: { size: "md" }
190
+ }
191
+ ), ee = x(
192
+ [
193
+ "ds:shrink-0 ds:rounded-none",
194
+ "ds:focus-visible:outline-none",
195
+ "ds:h-full",
196
+ "ds:gap-[var(--spacing-xs)]"
197
+ ].join(" ")
198
+ ), te = _(
199
+ ({
200
+ value: t,
201
+ size: e = "md",
202
+ intent: s = "default",
203
+ startIcon: o,
204
+ wrap: C = !1,
205
+ copyLabel: i,
206
+ copiedLabel: T,
207
+ copiedDuration: u = 2e3,
208
+ ariaLabel: n,
209
+ onCopy: a,
210
+ disabled: d = !1,
211
+ className: z,
212
+ id: c,
213
+ ...h
214
+ }, l) => {
215
+ const { t: r } = O(), g = m(t);
216
+ g.current = t;
217
+ const v = m(a);
218
+ v.current = a;
219
+ const { status: w, copy: I } = Q({
220
+ resetAfterMs: u,
221
+ writer: X
222
+ }), f = w === "copied", R = m(!1);
223
+ R.current = f;
224
+ const [B, F] = A("");
225
+ V(() => {
226
+ F(w === "copied" ? r("copyField.copySuccess") : w === "error" ? r("copyField.copyFailed") : "");
227
+ }, [w, r]);
228
+ const b = y(async () => {
229
+ var j;
230
+ if (d) return !1;
231
+ const L = await I(g.current);
232
+ return L && ((j = v.current) == null || j.call(v, g.current)), L;
233
+ }, [d, I]), N = y(() => {
234
+ b();
235
+ }, [b]), K = H(
236
+ () => ({
237
+ getValue: () => g.current,
238
+ copy: () => b(),
239
+ isCopied: () => R.current
240
+ }),
241
+ [b]
242
+ );
243
+ q(U, K, c);
244
+ const M = n ?? r("copyField.valueLabel"), S = i ?? r("copyField.copy"), k = T ?? r("copyField.copied"), E = f ? typeof k == "string" ? k : r("copyField.copied") : typeof S == "string" ? S : r("copyField.copy");
245
+ return /* @__PURE__ */ P(
246
+ "div",
247
+ {
248
+ ref: l,
249
+ className: Y({ size: e, disabled: d, className: z }),
250
+ "data-component": "copy-field",
251
+ "data-component-id": c,
252
+ "data-copied": f ? "true" : void 0,
253
+ ...h,
254
+ children: [
255
+ o ? /* @__PURE__ */ p("span", { "aria-hidden": "true", className: $({ size: e }), children: o }) : null,
256
+ /* @__PURE__ */ p(
257
+ "input",
258
+ {
259
+ id: c,
260
+ type: "text",
261
+ readOnly: !0,
262
+ value: t,
263
+ disabled: d,
264
+ "aria-label": M,
265
+ className: Z({
266
+ intent: s,
267
+ size: e,
268
+ wrap: C,
269
+ hasStartIcon: !!o
270
+ })
271
+ }
272
+ ),
273
+ /* @__PURE__ */ p(
274
+ W,
275
+ {
276
+ type: "button",
277
+ intent: "ghost",
278
+ size: e,
279
+ onClick: N,
280
+ disabled: d,
281
+ "aria-label": E,
282
+ className: ee(),
283
+ startIcon: f ? /* @__PURE__ */ p(D, { "aria-hidden": "true" }) : /* @__PURE__ */ p(G, { "aria-hidden": "true" }),
284
+ children: /* @__PURE__ */ p("span", { className: "type-label", children: f ? k : S })
285
+ }
286
+ ),
287
+ /* @__PURE__ */ p("span", { role: "status", "aria-live": "polite", className: "ds:sr-only", children: B })
288
+ ]
289
+ }
290
+ );
291
+ }
292
+ );
293
+ te.displayName = "CopyField";
294
+ export {
295
+ te as C,
296
+ U as c
297
+ };
298
+ //# sourceMappingURL=copy-field-BCHAZ8QV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-field-BCHAZ8QV.js","sources":["../../src/hooks/use-copy-to-clipboard.ts","../../src/components/copy-field/copy-field.agent.ts","../../src/components/copy-field/copy-field.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type CopyStatus = 'idle' | 'copied' | 'error';\n\nexport interface UseCopyToClipboardOptions {\n /**\n * Auto-reset to `'idle'` this many ms after a successful copy. Pass\n * `0` to disable auto-reset (caller drives the lifecycle). @default 2000\n */\n resetAfterMs?: number;\n /**\n * Override the underlying clipboard writer. When omitted the hook\n * uses `navigator.clipboard.writeText`. Pass your own writer to add\n * a legacy `document.execCommand('copy')` fallback for non-HTTPS\n * contexts, or to instrument the call for telemetry. Must resolve\n * `true` on success, `false` on failure (do not throw).\n */\n writer?: (value: string) => Promise<boolean>;\n}\n\nexport interface UseCopyToClipboardReturn {\n /** Current status. `'idle'` until the first `copy()` call. */\n status: CopyStatus;\n /** Last value successfully copied, or `null`. */\n copiedValue: string | null;\n /** Copy `value` to the clipboard. Returns `true` on success. */\n copy: (value: string) => Promise<boolean>;\n /** Reset to `'idle'` immediately. */\n reset: () => void;\n}\n\nconst SSR_FALLBACK_AVAILABLE =\n typeof navigator !== 'undefined' &&\n typeof navigator.clipboard !== 'undefined' &&\n typeof navigator.clipboard.writeText === 'function';\n\n/**\n * Copy a string to the system clipboard with status tracking.\n *\n * Uses `navigator.clipboard.writeText` (https-only / focus-required, but\n * universally available in modern browsers). Falls back gracefully —\n * `copy()` returns `false` and sets `status: 'error'` when the Clipboard\n * API is unavailable or the call rejects.\n *\n * Status auto-resets to `'idle'` after `resetAfterMs` ms by default so\n * the common \"show ✓ for 2s after click\" UX has zero glue code.\n *\n * @example\n * const { status, copy } = useCopyToClipboard();\n * <Button onClick={() => copy(value)}>\n * {status === 'copied' ? 'Copied!' : 'Copy'}\n * </Button>\n */\nexport function useCopyToClipboard(\n options: UseCopyToClipboardOptions = {},\n): UseCopyToClipboardReturn {\n const { resetAfterMs = 2000, writer } = options;\n\n // Mirror the writer in a ref so callers passing a fresh closure each\n // render don't churn the `copy` identity.\n const writerRef = useRef(writer);\n useEffect(() => {\n writerRef.current = writer;\n }, [writer]);\n\n const [status, setStatus] = useState<CopyStatus>('idle');\n const [copiedValue, setCopiedValue] = useState<string | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimer = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const reset = useCallback(() => {\n clearTimer();\n setStatus('idle');\n setCopiedValue(null);\n }, [clearTimer]);\n\n const copy = useCallback(\n async (value: string): Promise<boolean> => {\n clearTimer();\n\n const customWriter = writerRef.current;\n let ok = false;\n\n if (customWriter) {\n try {\n ok = await customWriter(value);\n } catch {\n ok = false;\n }\n } else {\n // Re-read availability at call time so a hook instantiated during\n // SSR still works on the client.\n const hasClipboard =\n SSR_FALLBACK_AVAILABLE ||\n (typeof navigator !== 'undefined' &&\n typeof navigator.clipboard !== 'undefined' &&\n typeof navigator.clipboard.writeText === 'function');\n\n if (!hasClipboard) {\n setStatus('error');\n setCopiedValue(null);\n return false;\n }\n\n try {\n await navigator.clipboard.writeText(value);\n ok = true;\n } catch {\n ok = false;\n }\n }\n\n if (!ok) {\n setStatus('error');\n setCopiedValue(null);\n return false;\n }\n\n setStatus('copied');\n setCopiedValue(value);\n\n if (resetAfterMs > 0) {\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n setStatus('idle');\n }, resetAfterMs);\n }\n return true;\n },\n [clearTimer, resetAfterMs],\n );\n\n useEffect(() => clearTimer, [clearTimer]);\n\n return { status, copiedValue, copy, reset };\n}\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — CopyField. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\n\n/**\n * Imperative handle for CopyField — agents can read the value and trigger a\n * programmatic copy. State stays scoped to identifiers + transient UI state;\n * never PHI (per PRS §Security).\n */\nexport interface CopyFieldHandle {\n /** Returns the read-only value currently displayed. */\n getValue: () => string;\n /** Triggers the clipboard write side-effect. */\n copy: () => Promise<boolean>;\n /** Returns true for the brief window after a successful copy. */\n isCopied: () => boolean;\n}\n\nexport const copyFieldAgent: AgentAdapter<CopyFieldHandle> = {\n id: 'copy-field',\n capabilities: [],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.copyField.state.value',\n description: 'The value displayed in the read-only field.',\n read: (handle) => handle.getValue(),\n },\n copied: {\n type: 'boolean',\n descriptionKey: 'ui.agent.copyField.state.copied',\n description: 'True for the brief window after a successful copy.',\n read: (handle) => handle.isCopied(),\n },\n },\n actions: {\n copy: {\n safety: 'write',\n descriptionKey: 'ui.agent.copyField.actions.copy',\n description: 'Programmatically trigger the clipboard write.',\n invoke: (handle) => handle.copy(),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'copy-field',\n description:\n 'Marks the CopyField root. The trailing button uses `aria-label` keyed off the copy / copied state.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop, when provided.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Check, Copy } from 'lucide-react';\nimport { Button } from '../button/button';\nimport { useAgentRegistration } from '../../agent';\nimport { useCopyToClipboard } from '../../hooks/use-copy-to-clipboard';\nimport { copyFieldAgent, type CopyFieldHandle } from './copy-field.agent';\n\n/* ------------------------------------------------------------------ */\n/* Clipboard helper */\n/* */\n/* `navigator.clipboard.writeText` is the modern path. The fallback */\n/* covers older browsers and insecure contexts via a synthesised */\n/* textarea + `document.execCommand('copy')`. The off-screen position */\n/* uses imperative DOM `.style` assignments — those are NOT JSX inline */\n/* styles and don't violate constraint §3. */\n/* ------------------------------------------------------------------ */\n\nasync function copyToClipboard(text: string): Promise<boolean> {\n if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n // fall through to legacy path\n }\n }\n if (typeof document === 'undefined') return false;\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n // Imperative DOM style — not a JSX inline-style violation. We use\n // `setProperty('inset-inline-start', …)` so the hidden textarea stays\n // logically off-screen in both LTR and RTL contexts.\n textarea.style.position = 'absolute';\n textarea.style.setProperty('inset-inline-start', '-9999px');\n document.body.appendChild(textarea);\n textarea.select();\n let ok = false;\n try {\n ok = document.execCommand('copy');\n } catch {\n ok = false;\n }\n document.body.removeChild(textarea);\n return ok;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA — outer wrapper */\n/* */\n/* Mirrors the shared input-surface chrome (border + halo shadow) so */\n/* CopyField sits inline next to TextInput / Combobox in forms without */\n/* visual drift. Logical paddings only. `ds:focus-within` paints the */\n/* ring when the trailing button or the embedded input receives focus. */\n/* ------------------------------------------------------------------ */\n\nconst fieldVariants = cva(\n [\n 'ds:inline-flex ds:items-stretch ds:w-full',\n 'ds:rounded-[var(--radius-sm)] ds:bg-input ds:text-foreground',\n 'ds:border ds:border-border',\n 'ds:shadow-[var(--shadow-input)]',\n 'ds:focus-within:outline-[length:var(--focus-ring-width)] ds:focus-within:outline-solid',\n 'ds:focus-within:outline-ring ds:focus-within:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-within:outline-[CanvasText]',\n 'ds:transition-[colors,box-shadow] ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:overflow-hidden',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:h-8 ds:text-[var(--font-size-sm)]',\n md: 'ds:h-[var(--min-target-size)] ds:text-[var(--font-size-base)]',\n lg: 'ds:h-12 ds:text-[var(--font-size-lg)]',\n },\n disabled: {\n true: 'ds:opacity-50 ds:cursor-not-allowed',\n false: '',\n },\n },\n defaultVariants: { size: 'md', disabled: false },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* CVA — value <input> styling */\n/* ------------------------------------------------------------------ */\n\nconst valueVariants = cva(\n [\n 'ds:flex-1 ds:min-w-0 ds:bg-transparent ds:border-0 ds:outline-none',\n 'ds:text-foreground',\n 'ds:disabled:cursor-not-allowed',\n ].join(' '),\n {\n variants: {\n intent: {\n default: '',\n // `--primary` is calibrated for foreground use (violet-500 light,\n // magenta-500 dark) — both pass AA against their input backgrounds.\n primary: 'ds:text-primary ds:font-medium',\n },\n size: {\n sm: 'ds:text-[var(--font-size-sm)]',\n md: 'ds:text-[var(--font-size-base)]',\n lg: 'ds:text-[var(--font-size-lg)]',\n },\n wrap: {\n true: 'ds:[overflow-wrap:anywhere] ds:whitespace-normal',\n false: 'ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap',\n },\n hasStartIcon: {\n true: '',\n false: '',\n },\n },\n // Explicit pairs decide the leading padding — single ps-* per cell, so\n // there's no fight between size + hasStartIcon under Tailwind's flat\n // utility precedence.\n compoundVariants: [\n { size: 'sm', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'md', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'lg', hasStartIcon: false, class: 'ds:ps-[var(--spacing-md)]' },\n { size: 'sm', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'md', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'lg', hasStartIcon: true, class: 'ds:ps-[var(--spacing-sm)]' },\n ],\n defaultVariants: {\n intent: 'default',\n size: 'md',\n wrap: false,\n hasStartIcon: false,\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Leading icon slot */\n/* ------------------------------------------------------------------ */\n\nconst startIconVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center ds:shrink-0',\n 'ds:text-muted-foreground',\n 'ds:[&_svg]:size-4',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:ps-[var(--spacing-sm)]',\n md: 'ds:ps-[var(--spacing-sm)]',\n lg: 'ds:ps-[var(--spacing-md)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Trailing button wrapper */\n/* */\n/* The button visually attaches to the field by removing its own focus */\n/* ring (the wrapper paints `focus-within`) and rounding only the */\n/* trailing inline-end corners. */\n/* ------------------------------------------------------------------ */\n\nconst copyButtonVariants = cva(\n [\n 'ds:shrink-0 ds:rounded-none',\n 'ds:focus-visible:outline-none',\n 'ds:h-full',\n 'ds:gap-[var(--spacing-xs)]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\ntype FieldSize = NonNullable<VariantProps<typeof fieldVariants>['size']>;\ntype ValueIntent = NonNullable<VariantProps<typeof valueVariants>['intent']>;\n\nexport interface CopyFieldProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'children' | 'onCopy'\n> {\n /** The value displayed in the read-only field and copied on click. */\n value: string;\n /** Field height + padding. Mirrors TextInput sizes. */\n size?: FieldSize;\n /**\n * `primary` tints the value text with `--primary` — matches the\n * link-style emphasis used by the telehealth showSession page.\n */\n intent?: ValueIntent;\n /**\n * Leading icon slot, decorative. Use `lucide-react` icons like\n * `<Link2 />` for a URL, `<KeyRound />` for a token.\n */\n startIcon?: ReactNode;\n /**\n * `false` (default) truncates long values with ellipsis on a single\n * line. `true` allows wrap with `overflow-wrap: anywhere`.\n */\n wrap?: boolean;\n /** Override the default 'Copy' button label. */\n copyLabel?: ReactNode;\n /** Override the default 'Copied' success-state label. */\n copiedLabel?: ReactNode;\n /** Milliseconds before the button reverts to its default state. Default 2000. */\n copiedDuration?: number;\n /** ARIA label for the read-only textbox. Defaults to the i18n key. */\n ariaLabel?: string;\n /** Fires once after a successful clipboard write. */\n onCopy?: (value: string) => void;\n /** Greys both the field and the button; the button doesn't fire onCopy. */\n disabled?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* CopyField */\n/* ------------------------------------------------------------------ */\n\nexport const CopyField = forwardRef<HTMLDivElement, CopyFieldProps>(\n (\n {\n value,\n size = 'md',\n intent = 'default',\n startIcon,\n wrap = false,\n copyLabel,\n copiedLabel,\n copiedDuration = 2000,\n ariaLabel,\n onCopy,\n disabled = false,\n className,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const valueRef = useRef(value);\n valueRef.current = value;\n const onCopyRef = useRef(onCopy);\n onCopyRef.current = onCopy;\n\n // Drive status + auto-reset from the shared hook. The custom `writer`\n // preserves CopyField's legacy `document.execCommand('copy')` fallback\n // for non-HTTPS / older-browser contexts.\n const { status, copy } = useCopyToClipboard({\n resetAfterMs: copiedDuration,\n writer: copyToClipboard,\n });\n const copied = status === 'copied';\n const copiedRef = useRef(false);\n copiedRef.current = copied;\n\n // i18n-aware live-region text mirrors the hook status — `copied` →\n // success message, `error` → failure message, `idle` → clear.\n const [liveRegionText, setLiveRegionText] = useState('');\n useEffect(() => {\n if (status === 'copied') {\n setLiveRegionText(t('copyField.copySuccess'));\n } else if (status === 'error') {\n setLiveRegionText(t('copyField.copyFailed'));\n } else {\n setLiveRegionText('');\n }\n }, [status, t]);\n\n const handleCopy = useCallback(async (): Promise<boolean> => {\n if (disabled) return false;\n const ok = await copy(valueRef.current);\n if (ok) onCopyRef.current?.(valueRef.current);\n return ok;\n }, [disabled, copy]);\n\n const handleButtonClick = useCallback(() => {\n void handleCopy();\n }, [handleCopy]);\n\n /* -------------------------------------------------------------- */\n /* Agent handle — read value + trigger copy + check transient state */\n /* -------------------------------------------------------------- */\n\n const agentHandle = useMemo<CopyFieldHandle>(\n () => ({\n getValue: () => valueRef.current,\n copy: () => handleCopy(),\n isCopied: () => copiedRef.current,\n }),\n [handleCopy],\n );\n useAgentRegistration(copyFieldAgent, agentHandle, id);\n\n const resolvedAriaLabel = ariaLabel ?? t('copyField.valueLabel');\n const resolvedCopyText = copyLabel ?? t('copyField.copy');\n const resolvedCopiedText = copiedLabel ?? t('copyField.copied');\n // `aria-label` must be a string; when the consumer passes a non-string\n // ReactNode for copyLabel / copiedLabel we fall back to the translated\n // default so AT users still hear a coherent name.\n const buttonAccessibleLabel = copied\n ? typeof resolvedCopiedText === 'string'\n ? resolvedCopiedText\n : t('copyField.copied')\n : typeof resolvedCopyText === 'string'\n ? resolvedCopyText\n : t('copyField.copy');\n\n return (\n <div\n ref={ref}\n className={fieldVariants({ size, disabled, className })}\n data-component=\"copy-field\"\n data-component-id={id}\n data-copied={copied ? 'true' : undefined}\n {...rest}\n >\n {startIcon ? (\n <span aria-hidden=\"true\" className={startIconVariants({ size })}>\n {startIcon}\n </span>\n ) : null}\n <input\n id={id}\n type=\"text\"\n readOnly\n value={value}\n disabled={disabled}\n aria-label={resolvedAriaLabel}\n className={valueVariants({\n intent,\n size,\n wrap,\n hasStartIcon: Boolean(startIcon),\n })}\n />\n <Button\n type=\"button\"\n intent=\"ghost\"\n size={size}\n onClick={handleButtonClick}\n disabled={disabled}\n aria-label={buttonAccessibleLabel}\n className={copyButtonVariants()}\n startIcon={\n copied ? <Check aria-hidden=\"true\" /> : <Copy aria-hidden=\"true\" />\n }\n >\n <span className=\"type-label\">\n {copied ? resolvedCopiedText : resolvedCopyText}\n </span>\n </Button>\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {liveRegionText}\n </span>\n </div>\n );\n },\n);\n\nCopyField.displayName = 'CopyField';\n"],"names":["SSR_FALLBACK_AVAILABLE","useCopyToClipboard","options","resetAfterMs","writer","writerRef","useRef","useEffect","status","setStatus","useState","copiedValue","setCopiedValue","timerRef","clearTimer","useCallback","reset","copy","value","customWriter","ok","copyFieldAgent","handle","copyToClipboard","text","_a","textarea","fieldVariants","cva","valueVariants","startIconVariants","copyButtonVariants","CopyField","forwardRef","size","intent","startIcon","wrap","copyLabel","copiedLabel","copiedDuration","ariaLabel","onCopy","disabled","className","id","rest","ref","t","useTranslation","valueRef","onCopyRef","copied","copiedRef","liveRegionText","setLiveRegionText","handleCopy","handleButtonClick","agentHandle","useMemo","useAgentRegistration","resolvedAriaLabel","resolvedCopyText","resolvedCopiedText","buttonAccessibleLabel","jsxs","jsx","Button","Check","Copy"],"mappings":"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"}