@glyphui/ui 0.1.0 → 0.2.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 (85) hide show
  1. package/README.md +1 -1
  2. package/dist/data-table.js +2 -2
  3. package/dist/{field-DXZD0l8w.js → field-CCecIzdq.js} +1 -1
  4. package/dist/{field-context-B8cYheXz.js → field-context-B6WOcK5m.js} +99 -99
  5. package/dist/form.js +2 -2
  6. package/dist/index.d.ts +2743 -93
  7. package/dist/index.js +2748 -111
  8. package/dist/{states-BxPjCUxz.js → states-Rp8wZ_jH.js} +1 -1
  9. package/package.json +4 -2
  10. package/src/components/accordion/accordion.styles.ts +41 -0
  11. package/src/components/accordion/accordion.tsx +86 -0
  12. package/src/components/accordion/index.ts +8 -0
  13. package/src/components/alert/alert-icons.tsx +66 -0
  14. package/src/components/alert/alert.styles.ts +57 -0
  15. package/src/components/alert/alert.tsx +86 -0
  16. package/src/components/alert/index.ts +2 -0
  17. package/src/components/alert-dialog/alert-dialog.styles.ts +24 -0
  18. package/src/components/alert-dialog/alert-dialog.tsx +118 -0
  19. package/src/components/alert-dialog/confirm.tsx +111 -0
  20. package/src/components/alert-dialog/index.ts +15 -0
  21. package/src/components/aspect-ratio/aspect-ratio.tsx +40 -0
  22. package/src/components/aspect-ratio/index.ts +1 -0
  23. package/src/components/badge/badge.styles.ts +1 -1
  24. package/src/components/banner/banner.styles.ts +40 -0
  25. package/src/components/banner/banner.tsx +101 -0
  26. package/src/components/banner/index.ts +2 -0
  27. package/src/components/blockquote/blockquote.tsx +59 -0
  28. package/src/components/blockquote/index.ts +1 -0
  29. package/src/components/breadcrumb/breadcrumb.styles.ts +20 -0
  30. package/src/components/breadcrumb/breadcrumb.tsx +135 -0
  31. package/src/components/breadcrumb/index.ts +12 -0
  32. package/src/components/button/button.tsx +11 -8
  33. package/src/components/code/code.styles.ts +33 -0
  34. package/src/components/code/code.tsx +96 -0
  35. package/src/components/code/index.ts +2 -0
  36. package/src/components/combobox/combobox.styles.ts +50 -0
  37. package/src/components/combobox/combobox.tsx +203 -0
  38. package/src/components/combobox/index.ts +2 -0
  39. package/src/components/command-menu/command-menu.styles.ts +41 -0
  40. package/src/components/command-menu/command-menu.tsx +217 -0
  41. package/src/components/command-menu/index.ts +14 -0
  42. package/src/components/description-list/description-list.styles.ts +31 -0
  43. package/src/components/description-list/description-list.tsx +56 -0
  44. package/src/components/description-list/index.ts +7 -0
  45. package/src/components/dialog/close-icon.tsx +22 -0
  46. package/src/components/dialog/dialog.styles.ts +41 -0
  47. package/src/components/dialog/dialog.tsx +111 -0
  48. package/src/components/dialog/index.ts +13 -0
  49. package/src/components/dropdown-menu/dropdown-menu.styles.ts +45 -0
  50. package/src/components/dropdown-menu/dropdown-menu.tsx +230 -0
  51. package/src/components/dropdown-menu/index.ts +19 -0
  52. package/src/components/grid/grid.tsx +144 -0
  53. package/src/components/grid/index.ts +1 -0
  54. package/src/components/link/index.ts +2 -0
  55. package/src/components/link/link.styles.ts +39 -0
  56. package/src/components/link/link.tsx +62 -0
  57. package/src/components/pagination/index.ts +3 -0
  58. package/src/components/pagination/pagination-range.ts +35 -0
  59. package/src/components/pagination/pagination.styles.ts +41 -0
  60. package/src/components/pagination/pagination.tsx +130 -0
  61. package/src/components/popover/index.ts +9 -0
  62. package/src/components/popover/popover.tsx +66 -0
  63. package/src/components/progress/index.ts +7 -0
  64. package/src/components/progress/progress.styles.ts +68 -0
  65. package/src/components/progress/progress.tsx +158 -0
  66. package/src/components/prose/index.ts +1 -0
  67. package/src/components/prose/prose.tsx +82 -0
  68. package/src/components/radio-group/index.ts +7 -0
  69. package/src/components/radio-group/radio-group.styles.ts +64 -0
  70. package/src/components/radio-group/radio-group.tsx +128 -0
  71. package/src/components/scroll-area/index.ts +1 -0
  72. package/src/components/scroll-area/scroll-area.tsx +68 -0
  73. package/src/components/sheet/index.ts +13 -0
  74. package/src/components/sheet/sheet.styles.ts +60 -0
  75. package/src/components/sheet/sheet.tsx +108 -0
  76. package/src/components/slider/index.ts +2 -0
  77. package/src/components/slider/slider.styles.ts +32 -0
  78. package/src/components/slider/slider.tsx +131 -0
  79. package/src/components/stat-card/index.ts +2 -0
  80. package/src/components/stat-card/stat-card.styles.ts +24 -0
  81. package/src/components/stat-card/stat-card.tsx +108 -0
  82. package/src/components/toast/index.ts +1 -0
  83. package/src/components/toast/toast.tsx +91 -0
  84. package/src/index.ts +25 -0
  85. package/src/provider/glyph-provider.tsx +16 -2
package/dist/index.js CHANGED
@@ -1,13 +1,479 @@
1
1
  "use client";
2
- import { A as useGlyph, C as popover, D as twMergeConfig, E as tv, O as useComponentConfig, S as focusRing, T as transition, _ as Button, b as Spinner, f as MenuIcon, g as XIcon, j as useLinkComponent, k as GlyphContext, m as PanelLeftIcon, n as useFieldControl, o as CheckIcon, s as ChevronDownIcon, t as FieldContext, v as IconButton, w as themedBorder, x as spinnerStyles, y as buttonStyles } from "./field-context-B8cYheXz.js";
3
- import { _ as inputStyles, a as Table, c as TableCell, d as TableRow, f as tableStyles, g as fieldControl, h as Input, i as stateStyles, l as TableHead, m as skeletonStyles, n as ErrorState, o as TableBody, p as Skeleton, r as LoadingState, s as TableCaption, t as EmptyState, u as TableHeader, v as Checkbox, y as checkboxStyles } from "./states-BxPjCUxz.js";
4
- import { i as labelStyles, n as fieldStyles, r as Label, t as Field } from "./field-DXZD0l8w.js";
2
+ import { A as useGlyph, C as MenuIcon, D as XIcon, E as SearchIcon, O as useComponentConfig, T as PanelLeftIcon, _ as CheckIcon$1, a as buttonStyles, b as ChevronRightIcon$1, c as tv, d as popover, f as themedBorder, i as IconButton, j as useLinkComponent, k as GlyphContext, l as twMergeConfig, n as useFieldControl, o as Spinner, p as transition, r as Button, s as spinnerStyles, t as FieldContext, u as focusRing, v as ChevronDownIcon, x as ChevronsUpDownIcon, y as ChevronLeftIcon } from "./field-context-B6WOcK5m.js";
3
+ import { _ as inputStyles, a as Table, c as TableCell, d as TableRow, f as tableStyles, g as fieldControl, h as Input, i as stateStyles, l as TableHead, m as skeletonStyles, n as ErrorState, o as TableBody, p as Skeleton, r as LoadingState, s as TableCaption, t as EmptyState, u as TableHeader, v as Checkbox, y as checkboxStyles } from "./states-Rp8wZ_jH.js";
4
+ import { i as labelStyles, n as fieldStyles, r as Label, t as Field } from "./field-CCecIzdq.js";
5
5
  import { defineTheme, defineTheme as defineTheme$1, presets as presets$1, scopeSelector, themeToCss, themeToCss as themeToCss$1, tokenVar } from "@glyphui/tokens";
6
- import { Avatar as Avatar$1, Dialog, Select as Select$1, Separator as Separator$1, Slot, Switch as Switch$1, Tabs as Tabs$1, ToggleGroup, Tooltip as Tooltip$1 } from "radix-ui";
7
- import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
+ import { Accordion as Accordion$1, AlertDialog as AlertDialog$1, AspectRatio as AspectRatio$1, Avatar as Avatar$1, Dialog as Dialog$1, DropdownMenu as DropdownMenu$1, Popover as Popover$1, Progress as Progress$1, RadioGroup as RadioGroup$1, ScrollArea as ScrollArea$1, Select as Select$1, Separator as Separator$1, Slider as Slider$1, Slot, Switch as Switch$1, Tabs as Tabs$1, ToggleGroup, Tooltip as Tooltip$1 } from "radix-ui";
7
+ import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
+ import { Command as Command$1 } from "cmdk";
10
+ import { Toaster as Toaster$1, toast } from "sonner";
9
11
  import { clsx } from "clsx";
10
12
  import { extendTailwindMerge } from "tailwind-merge";
13
+ //#region src/components/accordion/accordion.styles.ts
14
+ const accordionStyles = tv({
15
+ slots: {
16
+ root: "w-full",
17
+ item: "",
18
+ header: "flex",
19
+ trigger: [
20
+ "group flex flex-1 cursor-pointer items-center justify-between gap-4 rounded-xs py-4 text-left text-body font-medium text-foreground",
21
+ transition,
22
+ focusRing,
23
+ "hover:text-foreground/80 disabled:cursor-not-allowed disabled:opacity-50"
24
+ ],
25
+ chevron: "size-4 shrink-0 text-faint-foreground transition-transform duration-(--glyph-duration-base) ease-standard group-data-[state=open]:rotate-180",
26
+ content: "overflow-hidden text-small text-muted-foreground",
27
+ contentInner: "pb-4 transition-[opacity,translate] duration-(--glyph-duration-base) ease-standard starting:-translate-y-1 starting:opacity-0"
28
+ },
29
+ variants: { variant: {
30
+ default: { item: "border-b border-border last:border-b-0" },
31
+ separated: {
32
+ root: "grid gap-2",
33
+ item: ["rounded-lg border-border bg-surface px-4 shadow-xs", themedBorder]
34
+ }
35
+ } },
36
+ defaultVariants: { variant: "default" }
37
+ });
38
+ //#endregion
39
+ //#region src/components/accordion/accordion.tsx
40
+ const AccordionContext = createContext(null);
41
+ function useParts$4() {
42
+ return useContext(AccordionContext) ?? {
43
+ s: accordionStyles(),
44
+ slots: {}
45
+ };
46
+ }
47
+ /**
48
+ * Stacked sections that expand one at a time (`type="single"`, collapsible) or
49
+ * independently (`type="multiple"`). Good for FAQs and dense settings.
50
+ */
51
+ function Accordion(inProps) {
52
+ const [props, slots] = useComponentConfig("Accordion", inProps);
53
+ const { variant, className, ...rest } = props;
54
+ const s = accordionStyles({ variant });
55
+ return /* @__PURE__ */ jsx(AccordionContext.Provider, {
56
+ value: {
57
+ s,
58
+ slots
59
+ },
60
+ children: /* @__PURE__ */ jsx(Accordion$1.Root, {
61
+ "data-slot": "accordion",
62
+ className: s.root({ class: [slots.root, className] }),
63
+ ...rest
64
+ })
65
+ });
66
+ }
67
+ function AccordionItem({ className, ...props }) {
68
+ const { s, slots } = useParts$4();
69
+ return /* @__PURE__ */ jsx(Accordion$1.Item, {
70
+ "data-slot": "accordion-item",
71
+ className: s.item({ class: [slots.item, className] }),
72
+ ...props
73
+ });
74
+ }
75
+ function AccordionTrigger({ className, children, ...props }) {
76
+ const { s, slots } = useParts$4();
77
+ return /* @__PURE__ */ jsx(Accordion$1.Header, {
78
+ className: s.header({ class: slots.header }),
79
+ children: /* @__PURE__ */ jsxs(Accordion$1.Trigger, {
80
+ "data-slot": "accordion-trigger",
81
+ className: s.trigger({ class: [slots.trigger, className] }),
82
+ ...props,
83
+ children: [children, /* @__PURE__ */ jsx(ChevronDownIcon, { className: s.chevron({ class: slots.chevron }) })]
84
+ })
85
+ });
86
+ }
87
+ function AccordionContent({ className, children, ...props }) {
88
+ const { s, slots } = useParts$4();
89
+ return /* @__PURE__ */ jsx(Accordion$1.Content, {
90
+ "data-slot": "accordion-content",
91
+ className: s.content({ class: slots.content }),
92
+ ...props,
93
+ children: /* @__PURE__ */ jsx("div", {
94
+ className: s.contentInner({ class: [slots.contentInner, className] }),
95
+ children
96
+ })
97
+ });
98
+ }
99
+ //#endregion
100
+ //#region src/components/alert/alert.styles.ts
101
+ const alertStyles = tv({
102
+ slots: {
103
+ root: ["relative flex w-full items-start gap-3 rounded-md px-4 py-3 text-small", themedBorder],
104
+ icon: "mt-0.5 flex size-4 shrink-0 items-center justify-center [&>svg]:size-4",
105
+ content: "grid min-w-0 flex-1 gap-0.5",
106
+ title: "font-medium text-foreground",
107
+ description: "text-muted-foreground [&_a]:font-medium [&_a]:text-foreground [&_a]:underline [&_a]:underline-offset-2",
108
+ action: "flex shrink-0 items-center gap-2 self-center",
109
+ dismiss: "-my-1 -mr-2 shrink-0"
110
+ },
111
+ variants: {
112
+ tone: {
113
+ neutral: { icon: "text-muted-foreground" },
114
+ info: { icon: "text-[color-mix(in_oklab,var(--color-info)_80%,var(--color-foreground))]" },
115
+ success: { icon: "text-[color-mix(in_oklab,var(--color-success)_80%,var(--color-foreground))]" },
116
+ warning: { icon: "text-[color-mix(in_oklab,var(--color-warning)_80%,var(--color-foreground))]" },
117
+ danger: { icon: "text-[color-mix(in_oklab,var(--color-danger)_80%,var(--color-foreground))]" }
118
+ },
119
+ variant: {
120
+ soft: {},
121
+ outline: { root: "bg-surface" }
122
+ }
123
+ },
124
+ compoundVariants: [
125
+ {
126
+ variant: "soft",
127
+ tone: "neutral",
128
+ class: { root: "border-border bg-muted" }
129
+ },
130
+ {
131
+ variant: "soft",
132
+ tone: "info",
133
+ class: { root: "border-info/25 bg-info/8" }
134
+ },
135
+ {
136
+ variant: "soft",
137
+ tone: "success",
138
+ class: { root: "border-success/25 bg-success/8" }
139
+ },
140
+ {
141
+ variant: "soft",
142
+ tone: "warning",
143
+ class: { root: "border-warning/30 bg-warning/10" }
144
+ },
145
+ {
146
+ variant: "soft",
147
+ tone: "danger",
148
+ class: { root: "border-danger/25 bg-danger/8" }
149
+ },
150
+ {
151
+ variant: "outline",
152
+ tone: "neutral",
153
+ class: { root: "border-border-strong" }
154
+ },
155
+ {
156
+ variant: "outline",
157
+ tone: "info",
158
+ class: { root: "border-info/50" }
159
+ },
160
+ {
161
+ variant: "outline",
162
+ tone: "success",
163
+ class: { root: "border-success/50" }
164
+ },
165
+ {
166
+ variant: "outline",
167
+ tone: "warning",
168
+ class: { root: "border-warning/60" }
169
+ },
170
+ {
171
+ variant: "outline",
172
+ tone: "danger",
173
+ class: { root: "border-danger/50" }
174
+ }
175
+ ],
176
+ defaultVariants: {
177
+ tone: "neutral",
178
+ variant: "soft"
179
+ }
180
+ });
181
+ //#endregion
182
+ //#region src/components/alert/alert-icons.tsx
183
+ function Icon({ children, ...props }) {
184
+ return /* @__PURE__ */ jsx("svg", {
185
+ xmlns: "http://www.w3.org/2000/svg",
186
+ width: "16",
187
+ height: "16",
188
+ viewBox: "0 0 24 24",
189
+ fill: "none",
190
+ stroke: "currentColor",
191
+ strokeWidth: "2",
192
+ strokeLinecap: "round",
193
+ strokeLinejoin: "round",
194
+ "aria-hidden": "true",
195
+ ...props,
196
+ children
197
+ });
198
+ }
199
+ const InfoIcon = (p) => /* @__PURE__ */ jsxs(Icon, {
200
+ ...p,
201
+ children: [/* @__PURE__ */ jsx("circle", {
202
+ cx: "12",
203
+ cy: "12",
204
+ r: "10"
205
+ }), /* @__PURE__ */ jsx("path", { d: "M12 16v-4M12 8h.01" })]
206
+ });
207
+ const SuccessIcon = (p) => /* @__PURE__ */ jsxs(Icon, {
208
+ ...p,
209
+ children: [/* @__PURE__ */ jsx("circle", {
210
+ cx: "12",
211
+ cy: "12",
212
+ r: "10"
213
+ }), /* @__PURE__ */ jsx("path", { d: "m9 12 2 2 4-4" })]
214
+ });
215
+ const WarningIcon = (p) => /* @__PURE__ */ jsxs(Icon, {
216
+ ...p,
217
+ children: [/* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }), /* @__PURE__ */ jsx("path", { d: "M12 9v4M12 17h.01" })]
218
+ });
219
+ const DangerIcon = (p) => /* @__PURE__ */ jsxs(Icon, {
220
+ ...p,
221
+ children: [/* @__PURE__ */ jsx("circle", {
222
+ cx: "12",
223
+ cy: "12",
224
+ r: "10"
225
+ }), /* @__PURE__ */ jsx("path", { d: "m15 9-6 6M9 9l6 6" })]
226
+ });
227
+ const MegaphoneIcon = (p) => /* @__PURE__ */ jsxs(Icon, {
228
+ ...p,
229
+ children: [/* @__PURE__ */ jsx("path", { d: "m3 11 18-5v12L3 14v-3z" }), /* @__PURE__ */ jsx("path", { d: "M11.6 16.8a3 3 0 1 1-5.8-1.6" })]
230
+ });
231
+ /** The default icon for each tone. */
232
+ const toneIcons = {
233
+ neutral: () => /* @__PURE__ */ jsx(InfoIcon, {}),
234
+ primary: () => /* @__PURE__ */ jsx(MegaphoneIcon, {}),
235
+ info: () => /* @__PURE__ */ jsx(InfoIcon, {}),
236
+ success: () => /* @__PURE__ */ jsx(SuccessIcon, {}),
237
+ warning: () => /* @__PURE__ */ jsx(WarningIcon, {}),
238
+ danger: () => /* @__PURE__ */ jsx(DangerIcon, {})
239
+ };
240
+ //#endregion
241
+ //#region src/components/alert/alert.tsx
242
+ /**
243
+ * An inline message about the content around it. Danger and warning alerts are announced
244
+ * immediately (`role="alert"`); other tones politely (`role="status"`).
245
+ */
246
+ function Alert(inProps) {
247
+ const [props, slots] = useComponentConfig("Alert", inProps);
248
+ const { tone, variant, title, icon, action, onDismiss, dismissLabel = "Dismiss", className, children, ...rest } = props;
249
+ const resolvedTone = tone ?? "neutral";
250
+ const s = alertStyles({
251
+ tone,
252
+ variant
253
+ });
254
+ const iconNode = icon === false ? null : icon ?? toneIcons[resolvedTone]();
255
+ return /* @__PURE__ */ jsxs("div", {
256
+ "data-slot": "alert",
257
+ "data-tone": resolvedTone,
258
+ role: resolvedTone === "danger" || resolvedTone === "warning" ? "alert" : "status",
259
+ className: s.root({ class: [slots.root, className] }),
260
+ ...rest,
261
+ children: [
262
+ iconNode && /* @__PURE__ */ jsx("span", {
263
+ "data-slot": "alert-icon",
264
+ className: s.icon({ class: slots.icon }),
265
+ "aria-hidden": "true",
266
+ children: iconNode
267
+ }),
268
+ /* @__PURE__ */ jsxs("div", {
269
+ "data-slot": "alert-content",
270
+ className: s.content({ class: slots.content }),
271
+ children: [title && /* @__PURE__ */ jsx("p", {
272
+ "data-slot": "alert-title",
273
+ className: s.title({ class: slots.title }),
274
+ children: title
275
+ }), children && /* @__PURE__ */ jsx("div", {
276
+ "data-slot": "alert-description",
277
+ className: s.description({ class: slots.description }),
278
+ children
279
+ })]
280
+ }),
281
+ action && /* @__PURE__ */ jsx("div", {
282
+ "data-slot": "alert-action",
283
+ className: s.action({ class: slots.action }),
284
+ children: action
285
+ }),
286
+ onDismiss && /* @__PURE__ */ jsx(IconButton, {
287
+ size: "sm",
288
+ icon: /* @__PURE__ */ jsx(XIcon, {}),
289
+ "aria-label": dismissLabel,
290
+ onClick: onDismiss,
291
+ className: s.dismiss({ class: slots.dismiss })
292
+ })
293
+ ]
294
+ });
295
+ }
296
+ //#endregion
297
+ //#region src/components/alert-dialog/alert-dialog.styles.ts
298
+ const alertDialogStyles = tv({ slots: {
299
+ overlay: "fixed inset-0 z-50 animate-fade-in bg-overlay",
300
+ content: [
301
+ "fixed top-1/2 left-1/2 z-50 grid w-[calc(100vw-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 gap-5",
302
+ "rounded-xl border-border bg-surface p-6 text-foreground shadow-lg outline-none animate-pop-in",
303
+ themedBorder
304
+ ],
305
+ header: "flex flex-col gap-1.5",
306
+ title: "font-display text-h4 text-foreground",
307
+ description: "text-small text-muted-foreground",
308
+ footer: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"
309
+ } });
310
+ //#endregion
311
+ //#region src/components/alert-dialog/alert-dialog.tsx
312
+ function useParts$3() {
313
+ const [, slots] = useComponentConfig("AlertDialog", {});
314
+ return {
315
+ s: alertDialogStyles(),
316
+ slots
317
+ };
318
+ }
319
+ /**
320
+ * A modal that interrupts to ask for a decision, e.g. confirming a destructive action.
321
+ * Unlike Dialog it can't be dismissed by clicking outside. For a one-line confirm, use `useConfirm()`.
322
+ */
323
+ const AlertDialog = AlertDialog$1.Root;
324
+ const AlertDialogTrigger = AlertDialog$1.Trigger;
325
+ function AlertDialogContent(inProps) {
326
+ const [props, slots] = useComponentConfig("AlertDialog", inProps);
327
+ const { overlayClassName, className, ...rest } = props;
328
+ const s = alertDialogStyles();
329
+ return /* @__PURE__ */ jsxs(AlertDialog$1.Portal, { children: [/* @__PURE__ */ jsx(AlertDialog$1.Overlay, {
330
+ "data-slot": "alert-dialog-overlay",
331
+ className: s.overlay({ class: [slots.overlay, overlayClassName] })
332
+ }), /* @__PURE__ */ jsx(AlertDialog$1.Content, {
333
+ "data-slot": "alert-dialog-content",
334
+ className: s.content({ class: [slots.content, className] }),
335
+ ...rest
336
+ })] });
337
+ }
338
+ function AlertDialogHeader({ className, ...props }) {
339
+ const { s, slots } = useParts$3();
340
+ return /* @__PURE__ */ jsx("div", {
341
+ "data-slot": "alert-dialog-header",
342
+ className: s.header({ class: [slots.header, className] }),
343
+ ...props
344
+ });
345
+ }
346
+ function AlertDialogTitle({ className, ...props }) {
347
+ const { s, slots } = useParts$3();
348
+ return /* @__PURE__ */ jsx(AlertDialog$1.Title, {
349
+ "data-slot": "alert-dialog-title",
350
+ className: s.title({ class: [slots.title, className] }),
351
+ ...props
352
+ });
353
+ }
354
+ function AlertDialogDescription({ className, ...props }) {
355
+ const { s, slots } = useParts$3();
356
+ return /* @__PURE__ */ jsx(AlertDialog$1.Description, {
357
+ "data-slot": "alert-dialog-description",
358
+ className: s.description({ class: [slots.description, className] }),
359
+ ...props
360
+ });
361
+ }
362
+ function AlertDialogFooter({ className, ...props }) {
363
+ const { s, slots } = useParts$3();
364
+ return /* @__PURE__ */ jsx("div", {
365
+ "data-slot": "alert-dialog-footer",
366
+ className: s.footer({ class: [slots.footer, className] }),
367
+ ...props
368
+ });
369
+ }
370
+ /** The confirming button. Closes the dialog. */
371
+ function AlertDialogAction({ tone = "default", ...props }) {
372
+ return /* @__PURE__ */ jsx(AlertDialog$1.Action, {
373
+ asChild: true,
374
+ children: /* @__PURE__ */ jsx(Button, {
375
+ "data-slot": "alert-dialog-action",
376
+ variant: tone === "danger" ? "danger" : "primary",
377
+ ...props
378
+ })
379
+ });
380
+ }
381
+ /** The dismissing button. Receives focus when the dialog opens, so Enter never confirms by accident. */
382
+ function AlertDialogCancel(props) {
383
+ return /* @__PURE__ */ jsx(AlertDialog$1.Cancel, {
384
+ asChild: true,
385
+ children: /* @__PURE__ */ jsx(Button, {
386
+ "data-slot": "alert-dialog-cancel",
387
+ variant: "outline",
388
+ ...props
389
+ })
390
+ });
391
+ }
392
+ //#endregion
393
+ //#region src/components/alert-dialog/confirm.tsx
394
+ const ConfirmContext = createContext(null);
395
+ /**
396
+ * Enables `useConfirm()` for everything inside. Renders one shared AlertDialog.
397
+ * Mount once near the root (inside GlyphProvider).
398
+ */
399
+ function ConfirmProvider({ children }) {
400
+ const [pending, setPending] = useState(null);
401
+ const [open, setOpen] = useState(false);
402
+ const pendingRef = useRef(null);
403
+ const settle = useCallback((value) => {
404
+ pendingRef.current?.resolve(value);
405
+ pendingRef.current = null;
406
+ setOpen(false);
407
+ }, []);
408
+ const confirm = useCallback((options) => {
409
+ pendingRef.current?.resolve(false);
410
+ return new Promise((resolve) => {
411
+ const next = {
412
+ options,
413
+ resolve
414
+ };
415
+ pendingRef.current = next;
416
+ setPending(next);
417
+ setOpen(true);
418
+ });
419
+ }, []);
420
+ const value = useMemo(() => confirm, [confirm]);
421
+ const options = pending?.options;
422
+ const danger = options?.tone === "danger";
423
+ return /* @__PURE__ */ jsxs(ConfirmContext.Provider, {
424
+ value,
425
+ children: [children, /* @__PURE__ */ jsx(AlertDialog, {
426
+ open,
427
+ onOpenChange: (next) => !next && settle(false),
428
+ children: options && /* @__PURE__ */ jsxs(AlertDialogContent, { children: [/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: options.title }), options.description && /* @__PURE__ */ jsx(AlertDialogDescription, { children: options.description })] }), /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [/* @__PURE__ */ jsx(AlertDialogCancel, {
429
+ onClick: () => settle(false),
430
+ children: options.cancelLabel ?? "Cancel"
431
+ }), /* @__PURE__ */ jsx(AlertDialogAction, {
432
+ tone: options.tone,
433
+ onClick: () => settle(true),
434
+ children: options.confirmLabel ?? (danger ? "Delete" : "Confirm")
435
+ })] })] })
436
+ })]
437
+ });
438
+ }
439
+ /**
440
+ * Ask the user to confirm, in one line:
441
+ *
442
+ * ```tsx
443
+ * const confirm = useConfirm()
444
+ * if (await confirm({ title: 'Delete project?', tone: 'danger' })) await deleteProject()
445
+ * ```
446
+ *
447
+ * Resolves `true` when confirmed, `false` when cancelled or dismissed with Escape.
448
+ */
449
+ function useConfirm() {
450
+ const confirm = useContext(ConfirmContext);
451
+ if (!confirm) throw new Error("useConfirm must be used inside <ConfirmProvider> (or <GlyphProvider>).");
452
+ return confirm;
453
+ }
454
+ //#endregion
455
+ //#region src/components/aspect-ratio/aspect-ratio.tsx
456
+ const aspectRatioStyles = tv({
457
+ slots: { base: "overflow-hidden [&>img]:size-full [&>img]:object-cover [&>video]:size-full [&>video]:object-cover" },
458
+ variants: {
459
+ rounded: { true: { base: "rounded-lg" } },
460
+ placeholder: { true: { base: "bg-muted" } }
461
+ }
462
+ });
463
+ /** Keeps media at a fixed width-to-height ratio, e.g. `ratio={16 / 9}`. Images inside cover the box. */
464
+ function AspectRatio(inProps) {
465
+ const [props, slots] = useComponentConfig("AspectRatio", inProps);
466
+ const { rounded, placeholder, className, ...rest } = props;
467
+ return /* @__PURE__ */ jsx(AspectRatio$1.Root, {
468
+ "data-slot": "aspect-ratio",
469
+ className: aspectRatioStyles({
470
+ rounded,
471
+ placeholder
472
+ }).base({ class: [slots.base, className] }),
473
+ ...rest
474
+ });
475
+ }
476
+ //#endregion
11
477
  //#region src/components/avatar/avatar.styles.ts
12
478
  const avatarStyles = tv({
13
479
  slots: {
@@ -117,7 +583,7 @@ const tones = {
117
583
  const badgeStyles = tv({
118
584
  slots: {
119
585
  base: [
120
- "inline-flex h-5.5 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-pill border-transparent px-2",
586
+ "inline-flex h-5.5 w-fit shrink-0 items-center gap-1.5 whitespace-nowrap rounded-pill border-transparent px-2",
121
587
  "text-caption tabular-nums",
122
588
  themedBorder
123
589
  ],
@@ -171,6 +637,225 @@ function Badge(inProps) {
171
637
  });
172
638
  }
173
639
  //#endregion
640
+ //#region src/components/banner/banner.styles.ts
641
+ const bannerStyles = tv({
642
+ slots: {
643
+ root: ["w-full border-b-(length:--glyph-border-width) text-small"],
644
+ inner: "mx-auto flex w-full max-w-7xl items-center gap-3 px-4 py-2.5 sm:px-6",
645
+ icon: "flex size-4 shrink-0 items-center justify-center [&>svg]:size-4",
646
+ content: "min-w-0 flex-1 [&_a]:font-medium [&_a]:underline [&_a]:underline-offset-2",
647
+ action: "flex shrink-0 items-center gap-2",
648
+ dismiss: "-my-1 -mr-2 shrink-0 text-current hover:bg-current/10 hover:text-current"
649
+ },
650
+ variants: { tone: {
651
+ neutral: {
652
+ root: "border-border bg-subtle text-foreground",
653
+ icon: "text-muted-foreground"
654
+ },
655
+ primary: { root: "border-primary bg-primary text-primary-foreground" },
656
+ info: { root: "border-info/25 bg-info/10 text-[color-mix(in_oklab,var(--color-info)_55%,var(--color-foreground))]" },
657
+ success: { root: "border-success/25 bg-success/10 text-[color-mix(in_oklab,var(--color-success)_55%,var(--color-foreground))]" },
658
+ warning: { root: "border-warning/30 bg-warning/14 text-[color-mix(in_oklab,var(--color-warning)_50%,var(--color-foreground))]" },
659
+ danger: { root: "border-danger/25 bg-danger/10 text-[color-mix(in_oklab,var(--color-danger)_55%,var(--color-foreground))]" }
660
+ } },
661
+ defaultVariants: { tone: "neutral" }
662
+ });
663
+ //#endregion
664
+ //#region src/components/banner/banner.tsx
665
+ function readDismissed(key) {
666
+ if (!key || typeof window === "undefined") return false;
667
+ try {
668
+ return window.localStorage.getItem(key) === "dismissed";
669
+ } catch {
670
+ return false;
671
+ }
672
+ }
673
+ /** A full-width announcement at the top of a page or section. */
674
+ function Banner(inProps) {
675
+ const [props, slots] = useComponentConfig("Banner", inProps);
676
+ const { tone, icon, action, dismissible = false, storageKey, onDismiss, dismissLabel = "Dismiss", className, children, ...rest } = props;
677
+ const [dismissed, setDismissed] = useState(() => readDismissed(storageKey));
678
+ if (dismissed) return null;
679
+ const resolvedTone = tone ?? "neutral";
680
+ const s = bannerStyles({ tone });
681
+ const iconNode = icon === false ? null : icon ?? toneIcons[resolvedTone]();
682
+ const dismiss = () => {
683
+ setDismissed(true);
684
+ if (storageKey) try {
685
+ window.localStorage.setItem(storageKey, "dismissed");
686
+ } catch {}
687
+ onDismiss?.();
688
+ };
689
+ return /* @__PURE__ */ jsx("section", {
690
+ "data-slot": "banner",
691
+ "data-tone": resolvedTone,
692
+ "aria-label": "Announcement",
693
+ className: s.root({ class: [slots.root, className] }),
694
+ ...rest,
695
+ children: /* @__PURE__ */ jsxs("div", {
696
+ className: s.inner({ class: slots.inner }),
697
+ children: [
698
+ iconNode && /* @__PURE__ */ jsx("span", {
699
+ "data-slot": "banner-icon",
700
+ className: s.icon({ class: slots.icon }),
701
+ "aria-hidden": "true",
702
+ children: iconNode
703
+ }),
704
+ /* @__PURE__ */ jsx("div", {
705
+ "data-slot": "banner-content",
706
+ className: s.content({ class: slots.content }),
707
+ children
708
+ }),
709
+ action && /* @__PURE__ */ jsx("div", {
710
+ "data-slot": "banner-action",
711
+ className: s.action({ class: slots.action }),
712
+ children: action
713
+ }),
714
+ dismissible && /* @__PURE__ */ jsx(IconButton, {
715
+ size: "sm",
716
+ icon: /* @__PURE__ */ jsx(XIcon, {}),
717
+ "aria-label": dismissLabel,
718
+ onClick: dismiss,
719
+ className: s.dismiss({ class: slots.dismiss })
720
+ })
721
+ ]
722
+ })
723
+ });
724
+ }
725
+ //#endregion
726
+ //#region src/components/blockquote/blockquote.tsx
727
+ const blockquoteStyles = tv({
728
+ slots: {
729
+ root: "grid gap-3 border-l-2 border-primary pl-5",
730
+ quote: "font-display text-pretty text-foreground",
731
+ caption: "text-small text-muted-foreground",
732
+ author: "font-medium text-foreground not-italic"
733
+ },
734
+ variants: { size: {
735
+ sm: { quote: "text-body" },
736
+ md: { quote: "text-lead" },
737
+ lg: { quote: "text-h3" }
738
+ } },
739
+ defaultVariants: { size: "md" }
740
+ });
741
+ /** A quotation with an optional attribution. */
742
+ function Blockquote(inProps) {
743
+ const [props, slots] = useComponentConfig("Blockquote", inProps);
744
+ const { author, source, citeUrl, size, className, children, ...rest } = props;
745
+ const s = blockquoteStyles({ size });
746
+ return /* @__PURE__ */ jsxs("figure", {
747
+ "data-slot": "blockquote",
748
+ className: s.root({ class: [slots.root, className] }),
749
+ ...rest,
750
+ children: [/* @__PURE__ */ jsx("blockquote", {
751
+ cite: citeUrl,
752
+ className: s.quote({ class: slots.quote }),
753
+ children
754
+ }), (author || source) && /* @__PURE__ */ jsxs("figcaption", {
755
+ className: s.caption({ class: slots.caption }),
756
+ children: [
757
+ author && /* @__PURE__ */ jsx("cite", {
758
+ className: s.author({ class: slots.author }),
759
+ children: author
760
+ }),
761
+ author && source && ", ",
762
+ source
763
+ ]
764
+ })]
765
+ });
766
+ }
767
+ //#endregion
768
+ //#region src/components/breadcrumb/breadcrumb.styles.ts
769
+ const breadcrumbStyles = tv({ slots: {
770
+ root: "min-w-0",
771
+ list: "flex flex-wrap items-center gap-1.5 text-small text-muted-foreground",
772
+ item: "inline-flex min-w-0 items-center gap-1.5",
773
+ link: [
774
+ "truncate rounded-xs hover:text-foreground",
775
+ transition,
776
+ focusRing
777
+ ],
778
+ page: "truncate font-medium text-foreground",
779
+ separator: "flex items-center text-faint-foreground [&>svg]:size-3.5"
780
+ } });
781
+ //#endregion
782
+ //#region src/components/breadcrumb/breadcrumb.tsx
783
+ const s$2 = breadcrumbStyles();
784
+ function useSlots$2() {
785
+ return useComponentConfig("Breadcrumb", {})[1];
786
+ }
787
+ /** Shows where the current page sits in the hierarchy. */
788
+ function Breadcrumb({ items, separator, className, children, ...props }) {
789
+ const slots = useSlots$2();
790
+ return /* @__PURE__ */ jsx("nav", {
791
+ "aria-label": "Breadcrumb",
792
+ "data-slot": "breadcrumb",
793
+ className: s$2.root({ class: [slots.root, className] }),
794
+ ...props,
795
+ children: items ? /* @__PURE__ */ jsx(BreadcrumbList, { children: items.map((item, index) => {
796
+ const last = index === items.length - 1;
797
+ return /* @__PURE__ */ jsxs(BreadcrumbItem, { children: [last || !item.href ? /* @__PURE__ */ jsx(BreadcrumbPage, {
798
+ "aria-current": last ? "page" : void 0,
799
+ children: item.label
800
+ }) : /* @__PURE__ */ jsx(BreadcrumbLink, {
801
+ href: item.href,
802
+ children: item.label
803
+ }), !last && /* @__PURE__ */ jsx(BreadcrumbSeparator, { children: separator })] }, index);
804
+ }) }) : children
805
+ });
806
+ }
807
+ function BreadcrumbList({ className, ...props }) {
808
+ const slots = useSlots$2();
809
+ return /* @__PURE__ */ jsx("ol", {
810
+ "data-slot": "breadcrumb-list",
811
+ className: s$2.list({ class: [slots.list, className] }),
812
+ ...props
813
+ });
814
+ }
815
+ function BreadcrumbItem({ className, ...props }) {
816
+ const slots = useSlots$2();
817
+ return /* @__PURE__ */ jsx("li", {
818
+ "data-slot": "breadcrumb-item",
819
+ className: s$2.item({ class: [slots.item, className] }),
820
+ ...props
821
+ });
822
+ }
823
+ function BreadcrumbLink({ href, className, children, asChild }) {
824
+ const Link = useLinkComponent();
825
+ const slots = useSlots$2();
826
+ const classes = s$2.link({ class: [slots.link, className] });
827
+ if (asChild) return /* @__PURE__ */ jsx(Slot.Root, {
828
+ "data-slot": "breadcrumb-link",
829
+ className: classes,
830
+ children
831
+ });
832
+ return /* @__PURE__ */ jsx(Link, {
833
+ href,
834
+ className: classes,
835
+ children
836
+ });
837
+ }
838
+ function BreadcrumbPage({ className, ...props }) {
839
+ const slots = useSlots$2();
840
+ return /* @__PURE__ */ jsx("span", {
841
+ "data-slot": "breadcrumb-page",
842
+ "aria-current": "page",
843
+ className: s$2.page({ class: [slots.page, className] }),
844
+ ...props
845
+ });
846
+ }
847
+ function BreadcrumbSeparator({ className, children, ...props }) {
848
+ const slots = useSlots$2();
849
+ return /* @__PURE__ */ jsx("span", {
850
+ "data-slot": "breadcrumb-separator",
851
+ role: "presentation",
852
+ "aria-hidden": "true",
853
+ className: s$2.separator({ class: [slots.separator, className] }),
854
+ ...props,
855
+ children: children ?? /* @__PURE__ */ jsx(ChevronRightIcon$1, {})
856
+ });
857
+ }
858
+ //#endregion
174
859
  //#region src/components/card/card.styles.ts
175
860
  const cardStyles = tv({
176
861
  slots: {
@@ -277,98 +962,1698 @@ function CardFooter({ className, ...props }) {
277
962
  });
278
963
  }
279
964
  //#endregion
280
- //#region src/components/container/container.tsx
281
- const containerStyles = tv({
282
- base: "mx-auto w-full px-4 sm:px-6",
283
- variants: { size: {
284
- sm: "max-w-2xl",
285
- md: "max-w-3xl",
286
- lg: "max-w-5xl",
287
- xl: "max-w-7xl",
288
- full: "max-w-none"
289
- } },
290
- defaultVariants: { size: "xl" }
965
+ //#region src/components/code/code.styles.ts
966
+ const codeStyles = tv({ slots: { base: "rounded-xs bg-muted px-[0.3em] py-[0.15em] font-mono text-[0.875em] text-foreground" } });
967
+ const codeBlockStyles = tv({
968
+ slots: {
969
+ root: ["relative min-w-0 overflow-hidden rounded-lg border-border bg-subtle", themedBorder],
970
+ header: "flex min-h-10 items-center justify-between gap-2 border-b border-border py-1 pr-1.5 pl-4",
971
+ title: "truncate font-mono text-caption text-faint-foreground",
972
+ copy: "shrink-0",
973
+ floatingCopy: "absolute top-2 right-2",
974
+ pre: "overflow-x-auto p-4 font-mono text-small leading-relaxed text-foreground"
975
+ },
976
+ variants: { wrap: { true: { pre: "whitespace-pre-wrap break-words" } } }
291
977
  });
292
- /** Centers content at a readable max width with consistent side gutters. */
293
- function Container({ size, asChild, className, ...props }) {
294
- const Comp = asChild ? Slot.Root : "div";
295
- return /* @__PURE__ */ jsx(Comp, {
296
- "data-slot": "container",
297
- className: containerStyles({
298
- size,
299
- class: className
300
- }),
301
- ...props
978
+ //#endregion
979
+ //#region src/components/code/code.tsx
980
+ /** Inline code within running text. */
981
+ function Code(inProps) {
982
+ const [{ className, ...rest }, slots] = useComponentConfig("Code", inProps);
983
+ return /* @__PURE__ */ jsx("code", {
984
+ "data-slot": "code",
985
+ className: codeStyles().base({ class: [slots.base, className] }),
986
+ ...rest
987
+ });
988
+ }
989
+ const CopyIcon = () => /* @__PURE__ */ jsxs("svg", {
990
+ viewBox: "0 0 24 24",
991
+ fill: "none",
992
+ stroke: "currentColor",
993
+ strokeWidth: "2",
994
+ strokeLinecap: "round",
995
+ strokeLinejoin: "round",
996
+ "aria-hidden": "true",
997
+ children: [/* @__PURE__ */ jsx("rect", {
998
+ width: "14",
999
+ height: "14",
1000
+ x: "8",
1001
+ y: "8",
1002
+ rx: "2"
1003
+ }), /* @__PURE__ */ jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })]
1004
+ });
1005
+ /** A block of code with an optional file name and a copy button. No syntax highlighting is applied. */
1006
+ function CodeBlock(inProps) {
1007
+ const [props, slots] = useComponentConfig("CodeBlock", inProps);
1008
+ const { code, title, language, copyable = true, wrap, className, ...rest } = props;
1009
+ const [copied, setCopied] = useState(false);
1010
+ const timer = useRef(void 0);
1011
+ const s = codeBlockStyles({ wrap });
1012
+ const heading = title ?? language;
1013
+ useEffect(() => () => clearTimeout(timer.current), []);
1014
+ const copy = async () => {
1015
+ try {
1016
+ await navigator.clipboard.writeText(code);
1017
+ setCopied(true);
1018
+ clearTimeout(timer.current);
1019
+ timer.current = setTimeout(() => setCopied(false), 1600);
1020
+ } catch {}
1021
+ };
1022
+ const copyButton = copyable ? /* @__PURE__ */ jsx(IconButton, {
1023
+ size: "sm",
1024
+ icon: copied ? /* @__PURE__ */ jsx(CheckIcon$1, {}) : /* @__PURE__ */ jsx(CopyIcon, {}),
1025
+ "aria-label": copied ? "Copied" : "Copy code",
1026
+ onClick: copy,
1027
+ className: heading ? s.copy({ class: slots.copy }) : s.floatingCopy({ class: slots.floatingCopy })
1028
+ }) : null;
1029
+ return /* @__PURE__ */ jsxs("figure", {
1030
+ "data-slot": "code-block",
1031
+ className: s.root({ class: [slots.root, className] }),
1032
+ ...rest,
1033
+ children: [heading ? /* @__PURE__ */ jsxs("figcaption", {
1034
+ className: s.header({ class: slots.header }),
1035
+ children: [/* @__PURE__ */ jsx("span", {
1036
+ className: s.title({ class: slots.title }),
1037
+ children: heading
1038
+ }), copyButton]
1039
+ }) : copyButton, /* @__PURE__ */ jsx("pre", {
1040
+ className: s.pre({ class: slots.pre }),
1041
+ children: /* @__PURE__ */ jsx("code", { children: code })
1042
+ })]
1043
+ });
1044
+ }
1045
+ //#endregion
1046
+ //#region src/hooks/use-controllable-state.ts
1047
+ /** State that can be controlled by a parent (`value` + `onChange`) or left uncontrolled. */
1048
+ function useControllableState({ value, defaultValue, onChange }) {
1049
+ const [internal, setInternal] = useState(defaultValue);
1050
+ const isControlled = value !== void 0;
1051
+ const current = isControlled ? value : internal;
1052
+ const onChangeRef = useRef(onChange);
1053
+ onChangeRef.current = onChange;
1054
+ return [current, useCallback((next) => {
1055
+ const resolved = typeof next === "function" ? next(current) : next;
1056
+ if (!isControlled) setInternal(resolved);
1057
+ onChangeRef.current?.(resolved);
1058
+ }, [current, isControlled])];
1059
+ }
1060
+ //#endregion
1061
+ //#region src/components/combobox/combobox.styles.ts
1062
+ const comboboxStyles = tv({
1063
+ slots: {
1064
+ trigger: [
1065
+ ...fieldControl,
1066
+ "flex cursor-pointer items-center justify-between gap-2 px-3 text-left outline-none",
1067
+ "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/20",
1068
+ "disabled:cursor-not-allowed disabled:opacity-50"
1069
+ ],
1070
+ value: "flex min-w-0 flex-1 items-center gap-1 truncate",
1071
+ placeholder: "truncate text-faint-foreground",
1072
+ chip: "inline-flex h-5.5 max-w-40 shrink-0 items-center truncate rounded-pill bg-muted px-2 text-caption text-foreground",
1073
+ icon: "size-4 shrink-0 text-faint-foreground",
1074
+ content: [popover, "w-(--radix-popover-trigger-width) min-w-56 p-0"],
1075
+ search: "flex items-center gap-2 border-b border-border px-3 text-faint-foreground [&>svg]:size-4 [&>svg]:shrink-0",
1076
+ input: "h-10 w-full min-w-0 bg-transparent text-small text-foreground outline-none placeholder:text-faint-foreground",
1077
+ list: "max-h-72 overflow-y-auto overscroll-contain p-1",
1078
+ empty: "px-3 py-6 text-center text-small text-muted-foreground",
1079
+ item: ["relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-small text-foreground outline-none", "data-[selected=true]:bg-muted data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50"],
1080
+ itemText: "grid min-w-0 flex-1",
1081
+ itemDescription: "truncate text-caption text-faint-foreground",
1082
+ check: "size-4 shrink-0 text-primary"
1083
+ },
1084
+ variants: {
1085
+ size: {
1086
+ sm: { trigger: "min-h-(--glyph-control-sm) text-small" },
1087
+ md: { trigger: "min-h-(--glyph-control-md) text-small" },
1088
+ lg: { trigger: "min-h-(--glyph-control-lg) text-body" }
1089
+ },
1090
+ multiple: { true: {
1091
+ trigger: "py-1",
1092
+ value: "flex-wrap overflow-visible whitespace-normal"
1093
+ } }
1094
+ },
1095
+ defaultVariants: { size: "md" }
1096
+ });
1097
+ //#endregion
1098
+ //#region src/components/combobox/combobox.tsx
1099
+ function toArray$1(value) {
1100
+ if (value === void 0) return void 0;
1101
+ if (value === null) return [];
1102
+ return Array.isArray(value) ? [...value] : [value];
1103
+ }
1104
+ /**
1105
+ * A select with search, for long option lists. `multiple` allows several values, shown
1106
+ * as chips. The value type is inferred from `options`.
1107
+ */
1108
+ function Combobox(inProps) {
1109
+ const [props, slots] = useComponentConfig("Combobox", useFieldControl(inProps));
1110
+ const { options, multiple = false, placeholder = "Select…", searchPlaceholder = "Search…", emptyText = "No results", maxChips = 3, size, disabled, required, name, id, className, contentClassName, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid } = props;
1111
+ const onValueChange = props.onValueChange;
1112
+ const [open, setOpen] = useState(false);
1113
+ const [selected, setSelected] = useControllableState({
1114
+ value: toArray$1(props.value),
1115
+ defaultValue: toArray$1(props.defaultValue) ?? [],
1116
+ onChange: (next) => onValueChange?.(multiple ? next : next[0] ?? null)
1117
+ });
1118
+ const byValue = useMemo(() => new Map(options.map((o) => [o.value, o])), [options]);
1119
+ const s = comboboxStyles({
1120
+ size,
1121
+ multiple
1122
+ });
1123
+ const choose = (value) => {
1124
+ if (multiple) {
1125
+ setSelected(selected.includes(value) ? selected.filter((v) => v !== value) : [...selected, value]);
1126
+ return;
1127
+ }
1128
+ setSelected(selected[0] === value ? [] : [value]);
1129
+ setOpen(false);
1130
+ };
1131
+ const labels = selected.map((v) => byValue.get(v)?.label ?? v);
1132
+ let display;
1133
+ if (labels.length === 0) display = /* @__PURE__ */ jsx("span", {
1134
+ className: s.placeholder({ class: slots.placeholder }),
1135
+ children: placeholder
1136
+ });
1137
+ else if (multiple) {
1138
+ const shown = labels.slice(0, maxChips);
1139
+ display = /* @__PURE__ */ jsxs(Fragment$1, { children: [shown.map((label, i) => /* @__PURE__ */ jsx("span", {
1140
+ className: s.chip({ class: slots.chip }),
1141
+ children: label
1142
+ }, selected[i])), labels.length > shown.length && /* @__PURE__ */ jsxs("span", {
1143
+ className: s.chip({ class: slots.chip }),
1144
+ children: ["+", labels.length - shown.length]
1145
+ })] });
1146
+ } else display = /* @__PURE__ */ jsx("span", {
1147
+ className: "truncate",
1148
+ children: labels[0]
1149
+ });
1150
+ return /* @__PURE__ */ jsxs(Popover$1.Root, {
1151
+ open,
1152
+ onOpenChange: setOpen,
1153
+ children: [
1154
+ /* @__PURE__ */ jsx(Popover$1.Trigger, {
1155
+ asChild: true,
1156
+ children: /* @__PURE__ */ jsxs("button", {
1157
+ type: "button",
1158
+ id,
1159
+ role: "combobox",
1160
+ "aria-haspopup": "listbox",
1161
+ "aria-expanded": open,
1162
+ "aria-label": ariaLabel,
1163
+ "aria-describedby": ariaDescribedBy,
1164
+ "aria-invalid": ariaInvalid,
1165
+ "aria-required": required,
1166
+ disabled,
1167
+ "data-slot": "combobox-trigger",
1168
+ className: s.trigger({ class: [slots.trigger, className] }),
1169
+ children: [/* @__PURE__ */ jsx("span", {
1170
+ className: s.value({ class: slots.value }),
1171
+ children: display
1172
+ }), /* @__PURE__ */ jsx(ChevronsUpDownIcon, { className: s.icon({ class: slots.icon }) })]
1173
+ })
1174
+ }),
1175
+ name && selected.map((value) => /* @__PURE__ */ jsx("input", {
1176
+ type: "hidden",
1177
+ name,
1178
+ value
1179
+ }, value)),
1180
+ /* @__PURE__ */ jsx(Popover$1.Portal, { children: /* @__PURE__ */ jsx(Popover$1.Content, {
1181
+ align: "start",
1182
+ sideOffset: 4,
1183
+ "data-slot": "combobox-content",
1184
+ className: s.content({ class: [slots.content, contentClassName] }),
1185
+ children: /* @__PURE__ */ jsxs(Command$1, {
1186
+ loop: true,
1187
+ label: ariaLabel ?? "Options",
1188
+ children: [/* @__PURE__ */ jsxs("div", {
1189
+ className: s.search({ class: slots.search }),
1190
+ children: [/* @__PURE__ */ jsx(SearchIcon, {}), /* @__PURE__ */ jsx(Command$1.Input, {
1191
+ placeholder: searchPlaceholder,
1192
+ className: s.input({ class: slots.input })
1193
+ })]
1194
+ }), /* @__PURE__ */ jsxs(Command$1.List, {
1195
+ className: s.list({ class: slots.list }),
1196
+ children: [/* @__PURE__ */ jsx(Command$1.Empty, {
1197
+ className: s.empty({ class: slots.empty }),
1198
+ children: emptyText
1199
+ }), options.map((option) => {
1200
+ const checked = selected.includes(option.value);
1201
+ return /* @__PURE__ */ jsxs(Command$1.Item, {
1202
+ value: option.value,
1203
+ keywords: [option.label, ...option.keywords ?? []],
1204
+ disabled: option.disabled,
1205
+ onSelect: () => choose(option.value),
1206
+ "data-checked": checked || void 0,
1207
+ "aria-checked": checked,
1208
+ className: s.item({ class: slots.item }),
1209
+ children: [/* @__PURE__ */ jsxs("span", {
1210
+ className: s.itemText({ class: slots.itemText }),
1211
+ children: [/* @__PURE__ */ jsx("span", {
1212
+ className: "truncate",
1213
+ children: option.label
1214
+ }), option.description && /* @__PURE__ */ jsx("span", {
1215
+ className: s.itemDescription({ class: slots.itemDescription }),
1216
+ children: option.description
1217
+ })]
1218
+ }), checked && /* @__PURE__ */ jsx(CheckIcon$1, { className: s.check({ class: slots.check }) })]
1219
+ }, option.value);
1220
+ })]
1221
+ })]
1222
+ })
1223
+ }) })
1224
+ ]
1225
+ });
1226
+ }
1227
+ //#endregion
1228
+ //#region src/components/kbd/kbd.tsx
1229
+ const kbdStyles = tv({ slots: { base: "inline-flex h-5 min-w-5 items-center justify-center rounded-xs border border-border bg-muted px-1 font-mono text-[0.6875rem] font-medium text-muted-foreground shadow-xs" } });
1230
+ /** A keyboard key, e.g. `<Kbd>⌘K</Kbd>`. */
1231
+ function Kbd(inProps) {
1232
+ const [{ className, ...rest }, slots] = useComponentConfig("Kbd", inProps);
1233
+ return /* @__PURE__ */ jsx("kbd", {
1234
+ "data-slot": "kbd",
1235
+ className: kbdStyles().base({ class: [slots.base, className] }),
1236
+ ...rest
1237
+ });
1238
+ }
1239
+ //#endregion
1240
+ //#region src/components/command-menu/command-menu.styles.ts
1241
+ const commandMenuStyles = tv({ slots: {
1242
+ overlay: "fixed inset-0 z-50 animate-fade-in bg-overlay",
1243
+ content: ["fixed top-[12vh] left-1/2 z-50 w-[calc(100%-2rem)] max-w-xl -translate-x-1/2 overflow-hidden rounded-xl border-border bg-raised text-foreground shadow-lg outline-none animate-pop-in", themedBorder],
1244
+ root: "flex w-full flex-col overflow-hidden bg-raised text-foreground",
1245
+ search: "flex items-center gap-2.5 border-b border-border px-4 text-faint-foreground [&>svg]:size-4 [&>svg]:shrink-0",
1246
+ input: "h-12 w-full min-w-0 bg-transparent text-body text-foreground outline-none placeholder:text-faint-foreground",
1247
+ list: "max-h-[min(24rem,60vh)] overflow-y-auto overscroll-contain p-2",
1248
+ empty: "py-10 text-center text-small text-muted-foreground",
1249
+ group: [
1250
+ "overflow-hidden",
1251
+ "[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:pt-2 [&_[cmdk-group-heading]]:pb-1",
1252
+ "[&_[cmdk-group-heading]]:font-mono [&_[cmdk-group-heading]]:text-caption [&_[cmdk-group-heading]]:uppercase",
1253
+ "[&_[cmdk-group-heading]]:tracking-[0.1em] [&_[cmdk-group-heading]]:text-faint-foreground"
1254
+ ],
1255
+ item: ["relative flex h-10 cursor-pointer select-none items-center gap-3 rounded-md px-2.5 text-small text-foreground outline-none", "data-[selected=true]:bg-muted data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50"],
1256
+ itemIcon: "flex size-4 shrink-0 items-center justify-center text-muted-foreground [&>svg]:size-4",
1257
+ itemLabel: "min-w-0 flex-1 truncate",
1258
+ shortcut: "ml-auto flex shrink-0 items-center gap-1",
1259
+ separator: "-mx-2 my-1.5 h-px bg-border"
1260
+ } });
1261
+ //#endregion
1262
+ //#region src/components/command-menu/command-menu.tsx
1263
+ const s$1 = commandMenuStyles();
1264
+ const CommandMenuContext = createContext(null);
1265
+ function useSlots$1() {
1266
+ return useComponentConfig("CommandMenu", {})[1];
1267
+ }
1268
+ /**
1269
+ * A ⌘K command palette in a modal dialog: search, grouped actions, keyboard navigation.
1270
+ * Pair with `useCommandMenuShortcut(setOpen)` to open it from the keyboard.
1271
+ */
1272
+ function CommandMenu(inProps) {
1273
+ const [props, slots] = useComponentConfig("CommandMenu", inProps);
1274
+ const { open: openProp, defaultOpen = false, onOpenChange, label = "Command menu", loop = true, filter, className, children } = props;
1275
+ const [open, setOpen] = useControllableState({
1276
+ value: openProp,
1277
+ defaultValue: defaultOpen,
1278
+ onChange: onOpenChange
1279
+ });
1280
+ return /* @__PURE__ */ jsx(Dialog$1.Root, {
1281
+ open,
1282
+ onOpenChange: setOpen,
1283
+ children: /* @__PURE__ */ jsxs(Dialog$1.Portal, { children: [/* @__PURE__ */ jsx(Dialog$1.Overlay, { className: s$1.overlay({ class: slots.overlay }) }), /* @__PURE__ */ jsxs(Dialog$1.Content, {
1284
+ "data-slot": "command-menu",
1285
+ "aria-describedby": void 0,
1286
+ className: s$1.content({ class: [slots.content, className] }),
1287
+ children: [/* @__PURE__ */ jsx(Dialog$1.Title, {
1288
+ className: "sr-only",
1289
+ children: label
1290
+ }), /* @__PURE__ */ jsx(CommandMenuContext.Provider, {
1291
+ value: { close: () => setOpen(false) },
1292
+ children: /* @__PURE__ */ jsx(Command, {
1293
+ label,
1294
+ loop,
1295
+ ...filter && { filter },
1296
+ children
1297
+ })
1298
+ })]
1299
+ })] })
1300
+ });
1301
+ }
1302
+ /** The palette without a dialog, for inline search panels. */
1303
+ function Command({ className, ...props }) {
1304
+ const slots = useSlots$1();
1305
+ return /* @__PURE__ */ jsx(Command$1, {
1306
+ "data-slot": "command",
1307
+ className: s$1.root({ class: [slots.root, className] }),
1308
+ ...props
1309
+ });
1310
+ }
1311
+ function CommandInput({ className, ...props }) {
1312
+ const slots = useSlots$1();
1313
+ return /* @__PURE__ */ jsxs("div", {
1314
+ className: s$1.search({ class: slots.search }),
1315
+ children: [/* @__PURE__ */ jsx(SearchIcon, {}), /* @__PURE__ */ jsx(Command$1.Input, {
1316
+ "data-slot": "command-input",
1317
+ className: s$1.input({ class: [slots.input, className] }),
1318
+ ...props
1319
+ })]
1320
+ });
1321
+ }
1322
+ function CommandList({ className, ...props }) {
1323
+ const slots = useSlots$1();
1324
+ return /* @__PURE__ */ jsx(Command$1.List, {
1325
+ "data-slot": "command-list",
1326
+ className: s$1.list({ class: [slots.list, className] }),
1327
+ ...props
1328
+ });
1329
+ }
1330
+ function CommandEmpty({ className, children = "No results", ...props }) {
1331
+ const slots = useSlots$1();
1332
+ return /* @__PURE__ */ jsx(Command$1.Empty, {
1333
+ "data-slot": "command-empty",
1334
+ className: s$1.empty({ class: [slots.empty, className] }),
1335
+ ...props,
1336
+ children
1337
+ });
1338
+ }
1339
+ function CommandGroup({ className, ...props }) {
1340
+ const slots = useSlots$1();
1341
+ return /* @__PURE__ */ jsx(Command$1.Group, {
1342
+ "data-slot": "command-group",
1343
+ className: s$1.group({ class: [slots.group, className] }),
1344
+ ...props
1345
+ });
1346
+ }
1347
+ function CommandItem({ icon, shortcut, closeOnSelect = true, onSelect, className, children, ...props }) {
1348
+ const slots = useSlots$1();
1349
+ const menu = useContext(CommandMenuContext);
1350
+ const keys = shortcut === void 0 ? [] : typeof shortcut === "string" ? [shortcut] : shortcut;
1351
+ return /* @__PURE__ */ jsxs(Command$1.Item, {
1352
+ "data-slot": "command-item",
1353
+ onSelect: (value) => {
1354
+ onSelect?.(value);
1355
+ if (closeOnSelect) menu?.close();
1356
+ },
1357
+ className: s$1.item({ class: [slots.item, className] }),
1358
+ ...props,
1359
+ children: [
1360
+ icon && /* @__PURE__ */ jsx("span", {
1361
+ className: s$1.itemIcon({ class: slots.itemIcon }),
1362
+ "aria-hidden": "true",
1363
+ children: icon
1364
+ }),
1365
+ /* @__PURE__ */ jsx("span", {
1366
+ className: s$1.itemLabel({ class: slots.itemLabel }),
1367
+ children
1368
+ }),
1369
+ keys.length > 0 && /* @__PURE__ */ jsx("span", {
1370
+ className: s$1.shortcut({ class: slots.shortcut }),
1371
+ "aria-hidden": "true",
1372
+ children: keys.map((key) => /* @__PURE__ */ jsx(Kbd, { children: key }, key))
1373
+ })
1374
+ ]
1375
+ });
1376
+ }
1377
+ function CommandSeparator({ className, ...props }) {
1378
+ const slots = useSlots$1();
1379
+ return /* @__PURE__ */ jsx(Command$1.Separator, {
1380
+ "data-slot": "command-separator",
1381
+ className: s$1.separator({ class: [slots.separator, className] }),
1382
+ ...props
1383
+ });
1384
+ }
1385
+ /** Toggles a command menu with ⌘K (macOS) or Ctrl+K. Pass another key to change it. */
1386
+ function useCommandMenuShortcut(setOpen, key = "k") {
1387
+ useEffect(() => {
1388
+ const onKeyDown = (event) => {
1389
+ if (event.key.toLowerCase() === key.toLowerCase() && (event.metaKey || event.ctrlKey)) {
1390
+ event.preventDefault();
1391
+ setOpen((open) => !open);
1392
+ }
1393
+ };
1394
+ document.addEventListener("keydown", onKeyDown);
1395
+ return () => document.removeEventListener("keydown", onKeyDown);
1396
+ }, [setOpen, key]);
1397
+ }
1398
+ //#endregion
1399
+ //#region src/components/container/container.tsx
1400
+ const containerStyles = tv({
1401
+ base: "mx-auto w-full px-4 sm:px-6",
1402
+ variants: { size: {
1403
+ sm: "max-w-2xl",
1404
+ md: "max-w-3xl",
1405
+ lg: "max-w-5xl",
1406
+ xl: "max-w-7xl",
1407
+ full: "max-w-none"
1408
+ } },
1409
+ defaultVariants: { size: "xl" }
1410
+ });
1411
+ /** Centers content at a readable max width with consistent side gutters. */
1412
+ function Container({ size, asChild, className, ...props }) {
1413
+ const Comp = asChild ? Slot.Root : "div";
1414
+ return /* @__PURE__ */ jsx(Comp, {
1415
+ "data-slot": "container",
1416
+ className: containerStyles({
1417
+ size,
1418
+ class: className
1419
+ }),
1420
+ ...props
1421
+ });
1422
+ }
1423
+ //#endregion
1424
+ //#region src/components/description-list/description-list.styles.ts
1425
+ const descriptionListStyles = tv({
1426
+ slots: {
1427
+ root: "grid w-full",
1428
+ item: "grid min-w-0 gap-1",
1429
+ term: "text-small text-muted-foreground",
1430
+ details: "min-w-0 break-words text-small text-foreground"
1431
+ },
1432
+ variants: {
1433
+ layout: {
1434
+ stacked: { root: "gap-4" },
1435
+ inline: { item: "sm:grid-cols-[minmax(0,12rem)_1fr] sm:gap-4" }
1436
+ },
1437
+ dividers: {
1438
+ true: {
1439
+ root: "gap-0 divide-y divide-border",
1440
+ item: "py-3 first:pt-0 last:pb-0"
1441
+ },
1442
+ false: {}
1443
+ }
1444
+ },
1445
+ compoundVariants: [{
1446
+ layout: "inline",
1447
+ dividers: false,
1448
+ class: { root: "gap-3" }
1449
+ }],
1450
+ defaultVariants: {
1451
+ layout: "stacked",
1452
+ dividers: false
1453
+ }
1454
+ });
1455
+ //#endregion
1456
+ //#region src/components/description-list/description-list.tsx
1457
+ const DescriptionListContext = createContext(null);
1458
+ /**
1459
+ * Label–value pairs, such as account details or order metadata.
1460
+ * `layout="inline"` puts terms and details side by side from the `sm` breakpoint.
1461
+ */
1462
+ function DescriptionList(inProps) {
1463
+ const [props, slots] = useComponentConfig("DescriptionList", inProps);
1464
+ const { layout, dividers, className, ...rest } = props;
1465
+ const s = descriptionListStyles({
1466
+ layout,
1467
+ dividers
1468
+ });
1469
+ return /* @__PURE__ */ jsx(DescriptionListContext.Provider, {
1470
+ value: {
1471
+ s,
1472
+ slots
1473
+ },
1474
+ children: /* @__PURE__ */ jsx("dl", {
1475
+ "data-slot": "description-list",
1476
+ className: s.root({ class: [slots.root, className] }),
1477
+ ...rest
1478
+ })
1479
+ });
1480
+ }
1481
+ function DescriptionItem({ term, children, className, ...props }) {
1482
+ const ctx = useContext(DescriptionListContext);
1483
+ const s = ctx?.s ?? descriptionListStyles();
1484
+ const slots = ctx?.slots ?? {};
1485
+ return /* @__PURE__ */ jsxs("div", {
1486
+ "data-slot": "description-item",
1487
+ className: s.item({ class: [slots.item, className] }),
1488
+ ...props,
1489
+ children: [/* @__PURE__ */ jsx("dt", {
1490
+ "data-slot": "description-term",
1491
+ className: s.term({ class: slots.term }),
1492
+ children: term
1493
+ }), /* @__PURE__ */ jsx("dd", {
1494
+ "data-slot": "description-details",
1495
+ className: s.details({ class: slots.details }),
1496
+ children
1497
+ })]
1498
+ });
1499
+ }
1500
+ //#endregion
1501
+ //#region src/components/dialog/close-icon.tsx
1502
+ /** Local close icon so overlay components stay self-contained. */
1503
+ function CloseIcon(props) {
1504
+ return /* @__PURE__ */ jsx("svg", {
1505
+ xmlns: "http://www.w3.org/2000/svg",
1506
+ width: "16",
1507
+ height: "16",
1508
+ viewBox: "0 0 24 24",
1509
+ fill: "none",
1510
+ stroke: "currentColor",
1511
+ strokeWidth: "2",
1512
+ strokeLinecap: "round",
1513
+ strokeLinejoin: "round",
1514
+ "aria-hidden": "true",
1515
+ ...props,
1516
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" })
1517
+ });
1518
+ }
1519
+ //#endregion
1520
+ //#region src/components/dialog/dialog.styles.ts
1521
+ const dialogStyles = tv({
1522
+ slots: {
1523
+ overlay: "fixed inset-0 z-50 animate-fade-in bg-overlay",
1524
+ content: [
1525
+ "fixed top-1/2 left-1/2 z-50 grid max-h-[calc(100dvh-2rem)] w-[calc(100vw-2rem)] -translate-x-1/2 -translate-y-1/2 gap-5 overflow-y-auto",
1526
+ "rounded-xl border-border bg-surface p-6 text-foreground shadow-lg outline-none animate-pop-in",
1527
+ themedBorder
1528
+ ],
1529
+ close: [
1530
+ "absolute top-4 right-4 inline-flex size-7 cursor-pointer items-center justify-center rounded-sm text-muted-foreground hover:bg-muted hover:text-foreground [&>svg]:size-4",
1531
+ transition,
1532
+ focusRing
1533
+ ],
1534
+ header: "flex flex-col gap-1.5 pr-8",
1535
+ title: "font-display text-h4 text-foreground",
1536
+ description: "text-small text-muted-foreground",
1537
+ body: "min-w-0 text-small text-foreground",
1538
+ footer: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"
1539
+ },
1540
+ variants: { size: {
1541
+ sm: { content: "max-w-sm" },
1542
+ md: { content: "max-w-lg" },
1543
+ lg: { content: "max-w-2xl" },
1544
+ xl: { content: "max-w-4xl" }
1545
+ } },
1546
+ defaultVariants: { size: "md" }
1547
+ });
1548
+ //#endregion
1549
+ //#region src/components/dialog/dialog.tsx
1550
+ function useParts$2() {
1551
+ const [, slots] = useComponentConfig("Dialog", {});
1552
+ return {
1553
+ s: dialogStyles(),
1554
+ slots
1555
+ };
1556
+ }
1557
+ /** A modal window. Focus is trapped inside and returns to the trigger on close. */
1558
+ const Dialog = Dialog$1.Root;
1559
+ const DialogTrigger = Dialog$1.Trigger;
1560
+ const DialogClose = Dialog$1.Close;
1561
+ function DialogContent(inProps) {
1562
+ const [props, slots] = useComponentConfig("Dialog", inProps);
1563
+ const { size, showClose = true, overlayClassName, className, children, ...rest } = props;
1564
+ const s = dialogStyles({ size });
1565
+ return /* @__PURE__ */ jsxs(Dialog$1.Portal, { children: [/* @__PURE__ */ jsx(Dialog$1.Overlay, {
1566
+ "data-slot": "dialog-overlay",
1567
+ className: s.overlay({ class: [slots.overlay, overlayClassName] })
1568
+ }), /* @__PURE__ */ jsxs(Dialog$1.Content, {
1569
+ "data-slot": "dialog-content",
1570
+ className: s.content({ class: [slots.content, className] }),
1571
+ ...rest,
1572
+ children: [children, showClose && /* @__PURE__ */ jsx(Dialog$1.Close, {
1573
+ "data-slot": "dialog-close",
1574
+ "aria-label": "Close",
1575
+ className: s.close({ class: slots.close }),
1576
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
1577
+ })]
1578
+ })] });
1579
+ }
1580
+ function DialogHeader({ className, ...props }) {
1581
+ const { s, slots } = useParts$2();
1582
+ return /* @__PURE__ */ jsx("div", {
1583
+ "data-slot": "dialog-header",
1584
+ className: s.header({ class: [slots.header, className] }),
1585
+ ...props
1586
+ });
1587
+ }
1588
+ function DialogTitle({ className, ...props }) {
1589
+ const { s, slots } = useParts$2();
1590
+ return /* @__PURE__ */ jsx(Dialog$1.Title, {
1591
+ "data-slot": "dialog-title",
1592
+ className: s.title({ class: [slots.title, className] }),
1593
+ ...props
1594
+ });
1595
+ }
1596
+ function DialogDescription({ className, ...props }) {
1597
+ const { s, slots } = useParts$2();
1598
+ return /* @__PURE__ */ jsx(Dialog$1.Description, {
1599
+ "data-slot": "dialog-description",
1600
+ className: s.description({ class: [slots.description, className] }),
1601
+ ...props
1602
+ });
1603
+ }
1604
+ function DialogBody({ className, ...props }) {
1605
+ const { s, slots } = useParts$2();
1606
+ return /* @__PURE__ */ jsx("div", {
1607
+ "data-slot": "dialog-body",
1608
+ className: s.body({ class: [slots.body, className] }),
1609
+ ...props
1610
+ });
1611
+ }
1612
+ function DialogFooter({ className, ...props }) {
1613
+ const { s, slots } = useParts$2();
1614
+ return /* @__PURE__ */ jsx("div", {
1615
+ "data-slot": "dialog-footer",
1616
+ className: s.footer({ class: [slots.footer, className] }),
1617
+ ...props
1618
+ });
1619
+ }
1620
+ //#endregion
1621
+ //#region src/components/dropdown-menu/dropdown-menu.styles.ts
1622
+ const item = [
1623
+ "relative flex h-8 cursor-pointer select-none items-center gap-2 rounded-sm px-2 text-small text-foreground outline-none",
1624
+ "data-highlighted:bg-muted data-disabled:pointer-events-none data-disabled:opacity-50",
1625
+ "[&_svg]:size-4 [&_svg]:shrink-0"
1626
+ ];
1627
+ const dropdownMenuStyles = tv({
1628
+ slots: {
1629
+ content: [popover, "min-w-48 max-h-(--radix-dropdown-menu-content-available-height) overflow-y-auto p-1"],
1630
+ item,
1631
+ icon: "flex size-4 shrink-0 items-center justify-center text-muted-foreground",
1632
+ indicator: "absolute left-2 flex size-4 items-center justify-center text-primary",
1633
+ label: "px-2 pt-1.5 pb-1 text-caption font-medium text-faint-foreground",
1634
+ separator: "-mx-1 my-1 h-px bg-border",
1635
+ shortcut: "ml-auto pl-4 font-mono text-caption tracking-wider text-faint-foreground",
1636
+ subTrigger: [...item, "data-[state=open]:bg-muted"],
1637
+ subContent: [popover, "min-w-40 p-1"]
1638
+ },
1639
+ variants: {
1640
+ tone: {
1641
+ default: {},
1642
+ danger: {
1643
+ item: "text-danger data-highlighted:bg-danger/10",
1644
+ icon: "text-danger"
1645
+ }
1646
+ },
1647
+ inset: { true: {
1648
+ item: "pl-8",
1649
+ label: "pl-8"
1650
+ } }
1651
+ },
1652
+ defaultVariants: { tone: "default" }
1653
+ });
1654
+ //#endregion
1655
+ //#region src/components/dropdown-menu/dropdown-menu.tsx
1656
+ function useParts$1(tone, inset) {
1657
+ const [, slots] = useComponentConfig("DropdownMenu", {});
1658
+ return {
1659
+ s: dropdownMenuStyles({
1660
+ tone,
1661
+ inset
1662
+ }),
1663
+ slots
1664
+ };
1665
+ }
1666
+ const svg = {
1667
+ xmlns: "http://www.w3.org/2000/svg",
1668
+ viewBox: "0 0 24 24",
1669
+ fill: "none",
1670
+ stroke: "currentColor",
1671
+ strokeWidth: 2,
1672
+ strokeLinecap: "round",
1673
+ strokeLinejoin: "round"
1674
+ };
1675
+ const CheckIcon = () => /* @__PURE__ */ jsx("svg", {
1676
+ "aria-hidden": "true",
1677
+ ...svg,
1678
+ children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
1679
+ });
1680
+ const DotIcon = () => /* @__PURE__ */ jsx("svg", {
1681
+ "aria-hidden": "true",
1682
+ ...svg,
1683
+ children: /* @__PURE__ */ jsx("circle", {
1684
+ cx: "12",
1685
+ cy: "12",
1686
+ r: "4",
1687
+ fill: "currentColor"
1688
+ })
1689
+ });
1690
+ const ChevronRightIcon = () => /* @__PURE__ */ jsx("svg", {
1691
+ "aria-hidden": "true",
1692
+ ...svg,
1693
+ children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
1694
+ });
1695
+ /** A menu of actions opened from a button: row actions, account menus, "more" buttons. */
1696
+ const DropdownMenu = DropdownMenu$1.Root;
1697
+ const DropdownMenuTrigger = DropdownMenu$1.Trigger;
1698
+ const DropdownMenuGroup = DropdownMenu$1.Group;
1699
+ const DropdownMenuRadioGroup = DropdownMenu$1.RadioGroup;
1700
+ const DropdownMenuSub = DropdownMenu$1.Sub;
1701
+ function DropdownMenuContent(inProps) {
1702
+ const [props, slots] = useComponentConfig("DropdownMenu", inProps);
1703
+ const { sideOffset = 6, align = "start", className, ...rest } = props;
1704
+ const s = dropdownMenuStyles();
1705
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, { children: /* @__PURE__ */ jsx(DropdownMenu$1.Content, {
1706
+ "data-slot": "dropdown-menu-content",
1707
+ sideOffset,
1708
+ align,
1709
+ className: s.content({ class: [slots.content, className] }),
1710
+ ...rest
1711
+ }) });
1712
+ }
1713
+ function DropdownMenuItem({ icon, shortcut, tone, inset, className, children, ...props }) {
1714
+ const { s, slots } = useParts$1(tone, inset);
1715
+ return /* @__PURE__ */ jsxs(DropdownMenu$1.Item, {
1716
+ "data-slot": "dropdown-menu-item",
1717
+ "data-tone": tone ?? "default",
1718
+ className: s.item({ class: [slots.item, className] }),
1719
+ ...props,
1720
+ children: [
1721
+ icon && /* @__PURE__ */ jsx("span", {
1722
+ className: s.icon({ class: slots.icon }),
1723
+ "aria-hidden": "true",
1724
+ children: icon
1725
+ }),
1726
+ children,
1727
+ shortcut && /* @__PURE__ */ jsx(DropdownMenuShortcut, { children: shortcut })
1728
+ ]
1729
+ });
1730
+ }
1731
+ function DropdownMenuCheckboxItem({ className, children, ...props }) {
1732
+ const { s, slots } = useParts$1(void 0, true);
1733
+ return /* @__PURE__ */ jsxs(DropdownMenu$1.CheckboxItem, {
1734
+ "data-slot": "dropdown-menu-checkbox-item",
1735
+ className: s.item({ class: [slots.item, className] }),
1736
+ ...props,
1737
+ children: [/* @__PURE__ */ jsx("span", {
1738
+ className: s.indicator({ class: slots.indicator }),
1739
+ children: /* @__PURE__ */ jsx(DropdownMenu$1.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, {}) })
1740
+ }), children]
1741
+ });
1742
+ }
1743
+ function DropdownMenuRadioItem({ className, children, ...props }) {
1744
+ const { s, slots } = useParts$1(void 0, true);
1745
+ return /* @__PURE__ */ jsxs(DropdownMenu$1.RadioItem, {
1746
+ "data-slot": "dropdown-menu-radio-item",
1747
+ className: s.item({ class: [slots.item, className] }),
1748
+ ...props,
1749
+ children: [/* @__PURE__ */ jsx("span", {
1750
+ className: s.indicator({ class: slots.indicator }),
1751
+ children: /* @__PURE__ */ jsx(DropdownMenu$1.ItemIndicator, { children: /* @__PURE__ */ jsx(DotIcon, {}) })
1752
+ }), children]
1753
+ });
1754
+ }
1755
+ function DropdownMenuLabel({ inset, className, ...props }) {
1756
+ const { s, slots } = useParts$1(void 0, inset);
1757
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Label, {
1758
+ "data-slot": "dropdown-menu-label",
1759
+ className: s.label({ class: [slots.label, className] }),
1760
+ ...props
1761
+ });
1762
+ }
1763
+ function DropdownMenuSeparator({ className, ...props }) {
1764
+ const { s, slots } = useParts$1();
1765
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Separator, {
1766
+ "data-slot": "dropdown-menu-separator",
1767
+ className: s.separator({ class: [slots.separator, className] }),
1768
+ ...props
1769
+ });
1770
+ }
1771
+ function DropdownMenuShortcut({ className, ...props }) {
1772
+ const { s, slots } = useParts$1();
1773
+ return /* @__PURE__ */ jsx("span", {
1774
+ "data-slot": "dropdown-menu-shortcut",
1775
+ className: s.shortcut({ class: [slots.shortcut, className] }),
1776
+ ...props
1777
+ });
1778
+ }
1779
+ function DropdownMenuSubTrigger({ icon, className, children, ...props }) {
1780
+ const { s, slots } = useParts$1();
1781
+ return /* @__PURE__ */ jsxs(DropdownMenu$1.SubTrigger, {
1782
+ "data-slot": "dropdown-menu-sub-trigger",
1783
+ className: s.subTrigger({ class: [slots.subTrigger, className] }),
1784
+ ...props,
1785
+ children: [
1786
+ icon && /* @__PURE__ */ jsx("span", {
1787
+ className: s.icon({ class: slots.icon }),
1788
+ "aria-hidden": "true",
1789
+ children: icon
1790
+ }),
1791
+ children,
1792
+ /* @__PURE__ */ jsx("span", {
1793
+ className: "ml-auto flex text-faint-foreground",
1794
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
1795
+ })
1796
+ ]
1797
+ });
1798
+ }
1799
+ function DropdownMenuSubContent({ sideOffset = 4, className, ...props }) {
1800
+ const { s, slots } = useParts$1();
1801
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, { children: /* @__PURE__ */ jsx(DropdownMenu$1.SubContent, {
1802
+ "data-slot": "dropdown-menu-sub-content",
1803
+ sideOffset,
1804
+ className: s.subContent({ class: [slots.subContent, className] }),
1805
+ ...props
1806
+ }) });
1807
+ }
1808
+ //#endregion
1809
+ //#region src/components/eyebrow/eyebrow.styles.ts
1810
+ const eyebrowStyles = tv({
1811
+ slots: { base: "font-mono text-caption uppercase tracking-[0.12em]" },
1812
+ variants: { tone: {
1813
+ muted: { base: "text-muted-foreground" },
1814
+ primary: { base: "text-primary" }
1815
+ } },
1816
+ defaultVariants: { tone: "muted" }
1817
+ });
1818
+ //#endregion
1819
+ //#region src/components/eyebrow/eyebrow.tsx
1820
+ /** Small uppercase label that sits above a heading. */
1821
+ function Eyebrow(inProps) {
1822
+ const [props, slots] = useComponentConfig("Eyebrow", inProps);
1823
+ const { tone, asChild, className, ...rest } = props;
1824
+ const s = eyebrowStyles({ tone });
1825
+ const Comp = asChild ? Slot.Root : "p";
1826
+ return /* @__PURE__ */ jsx(Comp, {
1827
+ "data-slot": "eyebrow",
1828
+ className: s.base({ class: [slots.base, className] }),
1829
+ ...rest
1830
+ });
1831
+ }
1832
+ //#endregion
1833
+ //#region src/components/grid/grid.tsx
1834
+ const colClasses = {
1835
+ base: {
1836
+ 1: "grid-cols-1",
1837
+ 2: "grid-cols-2",
1838
+ 3: "grid-cols-3",
1839
+ 4: "grid-cols-4",
1840
+ 5: "grid-cols-5",
1841
+ 6: "grid-cols-6",
1842
+ 7: "grid-cols-7",
1843
+ 8: "grid-cols-8",
1844
+ 9: "grid-cols-9",
1845
+ 10: "grid-cols-10",
1846
+ 11: "grid-cols-11",
1847
+ 12: "grid-cols-12"
1848
+ },
1849
+ sm: {
1850
+ 1: "sm:grid-cols-1",
1851
+ 2: "sm:grid-cols-2",
1852
+ 3: "sm:grid-cols-3",
1853
+ 4: "sm:grid-cols-4",
1854
+ 5: "sm:grid-cols-5",
1855
+ 6: "sm:grid-cols-6",
1856
+ 7: "sm:grid-cols-7",
1857
+ 8: "sm:grid-cols-8",
1858
+ 9: "sm:grid-cols-9",
1859
+ 10: "sm:grid-cols-10",
1860
+ 11: "sm:grid-cols-11",
1861
+ 12: "sm:grid-cols-12"
1862
+ },
1863
+ md: {
1864
+ 1: "md:grid-cols-1",
1865
+ 2: "md:grid-cols-2",
1866
+ 3: "md:grid-cols-3",
1867
+ 4: "md:grid-cols-4",
1868
+ 5: "md:grid-cols-5",
1869
+ 6: "md:grid-cols-6",
1870
+ 7: "md:grid-cols-7",
1871
+ 8: "md:grid-cols-8",
1872
+ 9: "md:grid-cols-9",
1873
+ 10: "md:grid-cols-10",
1874
+ 11: "md:grid-cols-11",
1875
+ 12: "md:grid-cols-12"
1876
+ },
1877
+ lg: {
1878
+ 1: "lg:grid-cols-1",
1879
+ 2: "lg:grid-cols-2",
1880
+ 3: "lg:grid-cols-3",
1881
+ 4: "lg:grid-cols-4",
1882
+ 5: "lg:grid-cols-5",
1883
+ 6: "lg:grid-cols-6",
1884
+ 7: "lg:grid-cols-7",
1885
+ 8: "lg:grid-cols-8",
1886
+ 9: "lg:grid-cols-9",
1887
+ 10: "lg:grid-cols-10",
1888
+ 11: "lg:grid-cols-11",
1889
+ 12: "lg:grid-cols-12"
1890
+ },
1891
+ xl: {
1892
+ 1: "xl:grid-cols-1",
1893
+ 2: "xl:grid-cols-2",
1894
+ 3: "xl:grid-cols-3",
1895
+ 4: "xl:grid-cols-4",
1896
+ 5: "xl:grid-cols-5",
1897
+ 6: "xl:grid-cols-6",
1898
+ 7: "xl:grid-cols-7",
1899
+ 8: "xl:grid-cols-8",
1900
+ 9: "xl:grid-cols-9",
1901
+ 10: "xl:grid-cols-10",
1902
+ 11: "xl:grid-cols-11",
1903
+ 12: "xl:grid-cols-12"
1904
+ }
1905
+ };
1906
+ function colsToClasses(cols) {
1907
+ if (typeof cols === "number") return colClasses.base[cols];
1908
+ return Object.entries(cols).map(([bp, n]) => colClasses[bp][n]).join(" ");
1909
+ }
1910
+ const gridStyles = tv({
1911
+ slots: { base: "grid" },
1912
+ variants: {
1913
+ gap: {
1914
+ 0: { base: "gap-0" },
1915
+ 1: { base: "gap-1" },
1916
+ 2: { base: "gap-2" },
1917
+ 3: { base: "gap-3" },
1918
+ 4: { base: "gap-4" },
1919
+ 5: { base: "gap-5" },
1920
+ 6: { base: "gap-6" },
1921
+ 8: { base: "gap-8" },
1922
+ 10: { base: "gap-10" },
1923
+ 12: { base: "gap-12" }
1924
+ },
1925
+ align: {
1926
+ start: { base: "items-start" },
1927
+ center: { base: "items-center" },
1928
+ end: { base: "items-end" },
1929
+ stretch: { base: "items-stretch" }
1930
+ }
1931
+ },
1932
+ defaultVariants: { gap: 4 }
1933
+ });
1934
+ /** Responsive equal-width columns with spacing from the scale. */
1935
+ function Grid(inProps) {
1936
+ const [props, slots] = useComponentConfig("Grid", inProps);
1937
+ const { cols = 1, gap, align, asChild, className, ...rest } = props;
1938
+ const Comp = asChild ? Slot.Root : "div";
1939
+ return /* @__PURE__ */ jsx(Comp, {
1940
+ "data-slot": "grid",
1941
+ className: gridStyles({
1942
+ gap,
1943
+ align
1944
+ }).base({ class: [
1945
+ colsToClasses(cols),
1946
+ slots.base,
1947
+ className
1948
+ ] }),
1949
+ ...rest
1950
+ });
1951
+ }
1952
+ //#endregion
1953
+ //#region src/components/heading/heading.styles.ts
1954
+ const headingStyles = tv({
1955
+ slots: { base: "font-display text-balance text-foreground" },
1956
+ variants: { size: {
1957
+ display: { base: "text-display" },
1958
+ h1: { base: "text-h1" },
1959
+ h2: { base: "text-h2" },
1960
+ h3: { base: "text-h3" },
1961
+ h4: { base: "text-h4" }
1962
+ } }
1963
+ });
1964
+ //#endregion
1965
+ //#region src/components/heading/heading.tsx
1966
+ const sizeForLevel = {
1967
+ 1: "h1",
1968
+ 2: "h2",
1969
+ 3: "h3",
1970
+ 4: "h4",
1971
+ 5: "h4",
1972
+ 6: "h4"
1973
+ };
1974
+ /** A heading whose semantic level and visual size are set independently. */
1975
+ function Heading(inProps) {
1976
+ const [props, slots] = useComponentConfig("Heading", inProps);
1977
+ const { level = 2, size, asChild, className, ...rest } = props;
1978
+ const s = headingStyles({ size: size ?? sizeForLevel[level] });
1979
+ const Comp = asChild ? Slot.Root : `h${level}`;
1980
+ return /* @__PURE__ */ jsx(Comp, {
1981
+ "data-slot": "heading",
1982
+ className: s.base({ class: [slots.base, className] }),
1983
+ ...rest
1984
+ });
1985
+ }
1986
+ //#endregion
1987
+ //#region src/components/link/link.styles.ts
1988
+ const linkStyles = tv({
1989
+ slots: {
1990
+ base: [
1991
+ "inline-flex items-baseline gap-1 rounded-xs font-medium",
1992
+ "bg-[linear-gradient(currentColor,currentColor)] bg-[position:0_100%] bg-no-repeat",
1993
+ "transition-[background-size,color] duration-(--glyph-duration-base) ease-standard",
1994
+ focusRing
1995
+ ],
1996
+ icon: "size-3 shrink-0 self-center opacity-70"
1997
+ },
1998
+ variants: {
1999
+ tone: {
2000
+ default: { base: "text-foreground" },
2001
+ muted: { base: "text-muted-foreground hover:text-foreground" },
2002
+ primary: { base: "text-primary" }
2003
+ },
2004
+ underline: {
2005
+ hover: { base: "bg-[length:0%_1px] hover:bg-[length:100%_1px] focus-visible:bg-[length:100%_1px]" },
2006
+ always: { base: "bg-[length:100%_1px] hover:bg-[length:100%_2px]" },
2007
+ none: { base: "bg-none" }
2008
+ }
2009
+ },
2010
+ defaultVariants: {
2011
+ tone: "primary",
2012
+ underline: "hover"
2013
+ }
2014
+ });
2015
+ //#endregion
2016
+ //#region src/components/link/link.tsx
2017
+ const ExternalIcon = (props) => /* @__PURE__ */ jsx("svg", {
2018
+ viewBox: "0 0 24 24",
2019
+ fill: "none",
2020
+ stroke: "currentColor",
2021
+ strokeWidth: "2",
2022
+ strokeLinecap: "round",
2023
+ strokeLinejoin: "round",
2024
+ "aria-hidden": "true",
2025
+ ...props,
2026
+ children: /* @__PURE__ */ jsx("path", { d: "M7 17 17 7M7 7h10v10" })
2027
+ });
2028
+ /**
2029
+ * A text link with an animated underline. Internal links go through the provider's
2030
+ * `linkComponent` (your router); external links render a plain `<a>`.
2031
+ */
2032
+ function Link(inProps) {
2033
+ const [props, slots] = useComponentConfig("Link", inProps);
2034
+ const { href, external = false, tone, underline, className, children, ...rest } = props;
2035
+ const RouterLink = useLinkComponent();
2036
+ const s = linkStyles({
2037
+ tone,
2038
+ underline
2039
+ });
2040
+ const classes = s.base({ class: [slots.base, className] });
2041
+ if (external) return /* @__PURE__ */ jsxs("a", {
2042
+ "data-slot": "link",
2043
+ href,
2044
+ target: "_blank",
2045
+ rel: "noopener noreferrer",
2046
+ className: classes,
2047
+ ...rest,
2048
+ children: [
2049
+ children,
2050
+ /* @__PURE__ */ jsx(ExternalIcon, { className: s.icon({ class: slots.icon }) }),
2051
+ " ",
2052
+ /* @__PURE__ */ jsx("span", {
2053
+ className: "sr-only",
2054
+ children: "(opens in a new tab)"
2055
+ })
2056
+ ]
2057
+ });
2058
+ return /* @__PURE__ */ jsx(RouterLink, {
2059
+ "data-slot": "link",
2060
+ href,
2061
+ className: classes,
2062
+ ...rest,
2063
+ children
2064
+ });
2065
+ }
2066
+ //#endregion
2067
+ //#region src/components/pagination/pagination.styles.ts
2068
+ const paginationStyles = tv({
2069
+ slots: {
2070
+ root: "flex",
2071
+ list: "flex flex-wrap items-center gap-1",
2072
+ item: [
2073
+ "inline-flex shrink-0 cursor-pointer select-none items-center justify-center rounded-md font-medium tabular-nums text-muted-foreground",
2074
+ transition,
2075
+ focusRing,
2076
+ "hover:bg-muted hover:text-foreground",
2077
+ "aria-[current=page]:bg-primary aria-[current=page]:text-primary-foreground aria-[current=page]:shadow-xs",
2078
+ "disabled:pointer-events-none disabled:opacity-40 aria-disabled:pointer-events-none aria-disabled:opacity-40",
2079
+ "[&>svg]:size-4"
2080
+ ],
2081
+ ellipsis: "inline-flex items-center justify-center text-faint-foreground"
2082
+ },
2083
+ variants: { size: {
2084
+ sm: {
2085
+ item: "h-(--glyph-control-sm) min-w-(--glyph-control-sm) px-1.5 text-small",
2086
+ ellipsis: "h-(--glyph-control-sm) w-(--glyph-control-sm) text-small"
2087
+ },
2088
+ md: {
2089
+ item: "h-(--glyph-control-md) min-w-(--glyph-control-md) px-2 text-small",
2090
+ ellipsis: "h-(--glyph-control-md) w-(--glyph-control-md) text-small"
2091
+ }
2092
+ } },
2093
+ defaultVariants: { size: "md" }
2094
+ });
2095
+ //#endregion
2096
+ //#region src/components/pagination/pagination-range.ts
2097
+ /**
2098
+ * The page numbers to show, with `'ellipsis'` for gaps. Always includes the first and
2099
+ * last page and `siblingCount` pages on each side of the current one, and keeps the
2100
+ * number of items constant so the control doesn't jump in width.
2101
+ *
2102
+ * `paginationRange(6, 20)` → `[1, 'ellipsis', 5, 6, 7, 'ellipsis', 20]`
2103
+ */
2104
+ function paginationRange(page, pageCount, siblingCount = 1) {
2105
+ const count = Math.max(0, Math.floor(pageCount));
2106
+ if (count === 0) return [];
2107
+ const current = Math.min(Math.max(1, Math.floor(page)), count);
2108
+ if (count <= siblingCount * 2 + 5) return range(1, count);
2109
+ const left = Math.max(current - siblingCount, 1);
2110
+ const right = Math.min(current + siblingCount, count);
2111
+ const showLeftGap = left > 2;
2112
+ const showRightGap = right < count - 1;
2113
+ const edge = 3 + siblingCount * 2;
2114
+ if (!showLeftGap && showRightGap) return [
2115
+ ...range(1, edge),
2116
+ "ellipsis",
2117
+ count
2118
+ ];
2119
+ if (showLeftGap && !showRightGap) return [
2120
+ 1,
2121
+ "ellipsis",
2122
+ ...range(count - edge + 1, count)
2123
+ ];
2124
+ return [
2125
+ 1,
2126
+ "ellipsis",
2127
+ ...range(left, right),
2128
+ "ellipsis",
2129
+ count
2130
+ ];
2131
+ }
2132
+ function range(from, to) {
2133
+ return Array.from({ length: to - from + 1 }, (_, i) => from + i);
2134
+ }
2135
+ //#endregion
2136
+ //#region src/components/pagination/pagination.tsx
2137
+ const ChevronsLeftIcon = () => /* @__PURE__ */ jsx("svg", {
2138
+ viewBox: "0 0 24 24",
2139
+ fill: "none",
2140
+ stroke: "currentColor",
2141
+ strokeWidth: "2",
2142
+ strokeLinecap: "round",
2143
+ strokeLinejoin: "round",
2144
+ "aria-hidden": "true",
2145
+ children: /* @__PURE__ */ jsx("path", { d: "m11 17-5-5 5-5M18 17l-5-5 5-5" })
2146
+ });
2147
+ const ChevronsRightIcon = () => /* @__PURE__ */ jsx("svg", {
2148
+ viewBox: "0 0 24 24",
2149
+ fill: "none",
2150
+ stroke: "currentColor",
2151
+ strokeWidth: "2",
2152
+ strokeLinecap: "round",
2153
+ strokeLinejoin: "round",
2154
+ "aria-hidden": "true",
2155
+ children: /* @__PURE__ */ jsx("path", { d: "m6 17 5-5-5-5M13 17l5-5-5-5" })
2156
+ });
2157
+ /** Page navigation for long lists. Controlled: you own `page`. */
2158
+ function Pagination(inProps) {
2159
+ const [props, slots] = useComponentConfig("Pagination", inProps);
2160
+ const { page, pageCount, onPageChange, getHref, siblingCount = 1, showEdges = true, size, className, ...rest } = props;
2161
+ const Link = useLinkComponent();
2162
+ const s = paginationStyles({ size });
2163
+ const itemClass = s.item({ class: slots.item });
2164
+ const current = Math.min(Math.max(1, page), Math.max(1, pageCount));
2165
+ const control = (target, label, content, options = {}) => {
2166
+ const disabled = target < 1 || target > pageCount || target === current && !options.current;
2167
+ const shared = {
2168
+ "aria-label": label,
2169
+ "aria-current": options.current ? "page" : void 0,
2170
+ className: itemClass
2171
+ };
2172
+ if (getHref) {
2173
+ if (disabled) return /* @__PURE__ */ jsx("span", {
2174
+ "aria-disabled": "true",
2175
+ ...shared,
2176
+ children: content
2177
+ });
2178
+ return /* @__PURE__ */ jsx(Link, {
2179
+ href: getHref(target),
2180
+ onClick: () => onPageChange?.(target),
2181
+ ...shared,
2182
+ children: content
2183
+ });
2184
+ }
2185
+ return /* @__PURE__ */ jsx("button", {
2186
+ type: "button",
2187
+ disabled,
2188
+ onClick: () => onPageChange?.(target),
2189
+ ...shared,
2190
+ children: content
2191
+ });
2192
+ };
2193
+ return /* @__PURE__ */ jsx("nav", {
2194
+ "aria-label": "Pagination",
2195
+ "data-slot": "pagination",
2196
+ className: s.root({ class: [slots.root, className] }),
2197
+ ...rest,
2198
+ children: /* @__PURE__ */ jsxs("ul", {
2199
+ className: s.list({ class: slots.list }),
2200
+ children: [
2201
+ showEdges && /* @__PURE__ */ jsx("li", { children: control(1, "First page", /* @__PURE__ */ jsx(ChevronsLeftIcon, {})) }),
2202
+ /* @__PURE__ */ jsx("li", { children: control(current - 1, "Previous page", /* @__PURE__ */ jsx(ChevronLeftIcon, {})) }),
2203
+ paginationRange(current, pageCount, siblingCount).map((item, index) => item === "ellipsis" ? /* @__PURE__ */ jsx("li", {
2204
+ className: s.ellipsis({ class: slots.ellipsis }),
2205
+ "aria-hidden": "true",
2206
+ children: "…"
2207
+ }, `gap-${index}`) : /* @__PURE__ */ jsx("li", { children: control(item, `Page ${item}`, item, { current: item === current }) }, item)),
2208
+ /* @__PURE__ */ jsx("li", { children: control(current + 1, "Next page", /* @__PURE__ */ jsx(ChevronRightIcon$1, {})) }),
2209
+ showEdges && /* @__PURE__ */ jsx("li", { children: control(pageCount, "Last page", /* @__PURE__ */ jsx(ChevronsRightIcon, {})) })
2210
+ ]
2211
+ })
2212
+ });
2213
+ }
2214
+ //#endregion
2215
+ //#region src/components/popover/popover.tsx
2216
+ const popoverStyles = tv({ slots: {
2217
+ content: [popover, "w-72 max-w-[calc(100vw-2rem)] overflow-visible p-4 text-small outline-none"],
2218
+ arrow: "fill-raised"
2219
+ } });
2220
+ /** Floating content anchored to a trigger: quick settings, details, small forms. */
2221
+ const Popover = Popover$1.Root;
2222
+ const PopoverTrigger = Popover$1.Trigger;
2223
+ const PopoverAnchor = Popover$1.Anchor;
2224
+ const PopoverClose = Popover$1.Close;
2225
+ function PopoverContent(inProps) {
2226
+ const [props, slots] = useComponentConfig("Popover", inProps);
2227
+ const { showArrow = false, sideOffset = 6, align = "center", className, children, ...rest } = props;
2228
+ const s = popoverStyles();
2229
+ return /* @__PURE__ */ jsx(Popover$1.Portal, { children: /* @__PURE__ */ jsxs(Popover$1.Content, {
2230
+ "data-slot": "popover-content",
2231
+ sideOffset,
2232
+ align,
2233
+ className: s.content({ class: [slots.content, className] }),
2234
+ ...rest,
2235
+ children: [children, showArrow && /* @__PURE__ */ jsx(Popover$1.Arrow, {
2236
+ width: 12,
2237
+ height: 6,
2238
+ className: s.arrow({ class: slots.arrow })
2239
+ })]
2240
+ }) });
2241
+ }
2242
+ //#endregion
2243
+ //#region src/components/progress/progress.styles.ts
2244
+ const progressStyles = tv({
2245
+ slots: {
2246
+ root: "grid w-full gap-1.5",
2247
+ header: "flex items-baseline justify-between gap-3 text-small",
2248
+ label: "font-medium text-foreground",
2249
+ value: "tabular-nums text-muted-foreground",
2250
+ track: "relative w-full overflow-hidden rounded-pill bg-muted",
2251
+ indicator: ["h-full w-full rounded-pill transition-transform duration-(--glyph-duration-slow) ease-standard", "data-[state=indeterminate]:w-1/3 data-[state=indeterminate]:animate-pulse"]
2252
+ },
2253
+ variants: {
2254
+ size: {
2255
+ sm: { track: "h-1" },
2256
+ md: { track: "h-2" },
2257
+ lg: { track: "h-3" }
2258
+ },
2259
+ tone: {
2260
+ primary: { indicator: "bg-primary" },
2261
+ neutral: { indicator: "bg-foreground" },
2262
+ success: { indicator: "bg-success" },
2263
+ warning: { indicator: "bg-warning" },
2264
+ danger: { indicator: "bg-danger" }
2265
+ }
2266
+ },
2267
+ defaultVariants: {
2268
+ size: "md",
2269
+ tone: "primary"
2270
+ }
2271
+ });
2272
+ const progressCircleStyles = tv({
2273
+ slots: {
2274
+ root: "relative inline-flex shrink-0 items-center justify-center",
2275
+ svg: "size-full -rotate-90",
2276
+ track: "stroke-muted",
2277
+ indicator: "stroke-current transition-[stroke-dashoffset] duration-(--glyph-duration-slow) ease-standard",
2278
+ value: "absolute font-medium tabular-nums text-foreground"
2279
+ },
2280
+ variants: {
2281
+ size: {
2282
+ sm: {
2283
+ root: "size-6",
2284
+ value: "hidden"
2285
+ },
2286
+ md: {
2287
+ root: "size-10",
2288
+ value: "text-[0.625rem]"
2289
+ },
2290
+ lg: {
2291
+ root: "size-16",
2292
+ value: "text-small"
2293
+ }
2294
+ },
2295
+ tone: {
2296
+ primary: { indicator: "text-primary" },
2297
+ neutral: { indicator: "text-foreground" },
2298
+ success: { indicator: "text-success" },
2299
+ warning: { indicator: "text-warning" },
2300
+ danger: { indicator: "text-danger" }
2301
+ }
2302
+ },
2303
+ defaultVariants: {
2304
+ size: "md",
2305
+ tone: "primary"
2306
+ }
2307
+ });
2308
+ //#endregion
2309
+ //#region src/components/progress/progress.tsx
2310
+ function clampPercent(value, max) {
2311
+ if (max <= 0) return 0;
2312
+ return Math.min(100, Math.max(0, value / max * 100));
2313
+ }
2314
+ const defaultFormat = (value, max) => `${Math.round(clampPercent(value, max))}%`;
2315
+ /** A horizontal bar showing how far a task has progressed. */
2316
+ function Progress(inProps) {
2317
+ const [props, slots] = useComponentConfig("Progress", inProps);
2318
+ const { value = null, max = 100, label, showValue = false, formatValue = defaultFormat, size, tone, className, "aria-label": ariaLabel, ...rest } = props;
2319
+ const labelId = useId();
2320
+ const s = progressStyles({
2321
+ size,
2322
+ tone
2323
+ });
2324
+ const determinate = typeof value === "number";
2325
+ const percent = determinate ? clampPercent(value, max) : 0;
2326
+ const valueText = determinate ? formatValue(value, max) : void 0;
2327
+ return /* @__PURE__ */ jsxs("div", {
2328
+ "data-slot": "progress",
2329
+ className: s.root({ class: [slots.root, className] }),
2330
+ ...rest,
2331
+ children: [(label || showValue && valueText) && /* @__PURE__ */ jsxs("div", {
2332
+ "data-slot": "progress-header",
2333
+ className: s.header({ class: slots.header }),
2334
+ children: [label && /* @__PURE__ */ jsx("span", {
2335
+ id: labelId,
2336
+ className: s.label({ class: slots.label }),
2337
+ children: label
2338
+ }), showValue && valueText && /* @__PURE__ */ jsx("span", {
2339
+ className: s.value({ class: slots.value }),
2340
+ "aria-hidden": "true",
2341
+ children: valueText
2342
+ })]
2343
+ }), /* @__PURE__ */ jsx(Progress$1.Root, {
2344
+ "data-slot": "progress-track",
2345
+ value: determinate ? Math.min(Math.max(value, 0), max) : null,
2346
+ max,
2347
+ getValueLabel: (v, m) => formatValue(v, m),
2348
+ "aria-labelledby": label ? labelId : void 0,
2349
+ "aria-label": label ? void 0 : ariaLabel,
2350
+ className: s.track({ class: slots.track }),
2351
+ children: /* @__PURE__ */ jsx(Progress$1.Indicator, {
2352
+ "data-slot": "progress-indicator",
2353
+ className: s.indicator({ class: slots.indicator }),
2354
+ style: determinate ? { transform: `translateX(-${100 - percent}%)` } : void 0
2355
+ })
2356
+ })]
2357
+ });
2358
+ }
2359
+ const RADIUS = 16;
2360
+ const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
2361
+ /** A compact ring for progress or a share of a total. */
2362
+ function ProgressCircle(inProps) {
2363
+ const [props, slots] = useComponentConfig("ProgressCircle", inProps);
2364
+ const { value, max = 100, showValue = false, formatValue = defaultFormat, size, tone, className, ...rest } = props;
2365
+ const s = progressCircleStyles({
2366
+ size,
2367
+ tone
2368
+ });
2369
+ const percent = clampPercent(value, max);
2370
+ const valueText = formatValue(value, max);
2371
+ return /* @__PURE__ */ jsxs("div", {
2372
+ "data-slot": "progress-circle",
2373
+ role: "progressbar",
2374
+ "aria-valuemin": 0,
2375
+ "aria-valuemax": max,
2376
+ "aria-valuenow": Math.min(Math.max(value, 0), max),
2377
+ "aria-valuetext": valueText,
2378
+ className: s.root({ class: [slots.root, className] }),
2379
+ ...rest,
2380
+ children: [/* @__PURE__ */ jsxs("svg", {
2381
+ viewBox: "0 0 40 40",
2382
+ className: s.svg({ class: slots.svg }),
2383
+ "aria-hidden": "true",
2384
+ children: [/* @__PURE__ */ jsx("circle", {
2385
+ cx: "20",
2386
+ cy: "20",
2387
+ r: RADIUS,
2388
+ fill: "none",
2389
+ strokeWidth: "4",
2390
+ className: s.track({ class: slots.track })
2391
+ }), /* @__PURE__ */ jsx("circle", {
2392
+ cx: "20",
2393
+ cy: "20",
2394
+ r: RADIUS,
2395
+ fill: "none",
2396
+ strokeWidth: "4",
2397
+ strokeLinecap: "round",
2398
+ strokeDasharray: CIRCUMFERENCE,
2399
+ strokeDashoffset: CIRCUMFERENCE * (1 - percent / 100),
2400
+ className: s.indicator({ class: slots.indicator })
2401
+ })]
2402
+ }), showValue && /* @__PURE__ */ jsx("span", {
2403
+ className: s.value({ class: slots.value }),
2404
+ "aria-hidden": "true",
2405
+ children: valueText
2406
+ })]
302
2407
  });
303
2408
  }
304
2409
  //#endregion
305
- //#region src/components/eyebrow/eyebrow.styles.ts
306
- const eyebrowStyles = tv({
307
- slots: { base: "font-mono text-caption uppercase tracking-[0.12em]" },
308
- variants: { tone: {
309
- muted: { base: "text-muted-foreground" },
310
- primary: { base: "text-primary" }
311
- } },
312
- defaultVariants: { tone: "muted" }
2410
+ //#region src/components/prose/prose.tsx
2411
+ /**
2412
+ * Element styles for long-form content. Every value comes from theme tokens, so articles
2413
+ * pick up the theme's display font, type scale, colors and radius.
2414
+ */
2415
+ const proseStyles = tv({
2416
+ slots: { base: [
2417
+ "text-foreground [&>:first-child]:mt-0 [&>:last-child]:mb-0",
2418
+ "[&_h1]:mt-[1.4em] [&_h1]:mb-[0.5em] [&_h1]:font-display [&_h1]:text-h1 [&_h1]:text-balance",
2419
+ "[&_h2]:mt-[1.6em] [&_h2]:mb-[0.5em] [&_h2]:font-display [&_h2]:text-h2 [&_h2]:text-balance",
2420
+ "[&_h3]:mt-[1.5em] [&_h3]:mb-[0.4em] [&_h3]:font-display [&_h3]:text-h3 [&_h3]:text-balance",
2421
+ "[&_h4]:mt-[1.4em] [&_h4]:mb-[0.4em] [&_h4]:font-display [&_h4]:text-h4",
2422
+ "[&_p]:my-[1em] [&_p]:text-pretty",
2423
+ "[&_strong]:font-semibold [&_strong]:text-foreground",
2424
+ "[&_a]:font-medium [&_a]:text-primary [&_a]:underline [&_a]:decoration-primary/40 [&_a]:underline-offset-4 [&_a:hover]:decoration-primary",
2425
+ "[&_ul]:my-[1em] [&_ul]:list-disc [&_ul]:pl-[1.5em] [&_ol]:my-[1em] [&_ol]:list-decimal [&_ol]:pl-[1.5em]",
2426
+ "[&_li]:my-[0.35em] [&_li]:pl-[0.25em] [&_li::marker]:text-faint-foreground",
2427
+ "[&_blockquote]:my-[1.5em] [&_blockquote]:border-l-2 [&_blockquote]:border-primary [&_blockquote]:pl-[1em] [&_blockquote]:font-display [&_blockquote]:text-muted-foreground",
2428
+ "[&_:not(pre)>code]:rounded-xs [&_:not(pre)>code]:bg-muted [&_:not(pre)>code]:px-[0.3em] [&_:not(pre)>code]:py-[0.15em] [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-[0.875em]",
2429
+ "[&_pre]:my-[1.5em] [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:border [&_pre]:border-border [&_pre]:bg-subtle [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-small [&_pre]:leading-relaxed",
2430
+ "[&_hr]:my-[2em] [&_hr]:border-border",
2431
+ "[&_img]:my-[1.5em] [&_img]:max-w-full [&_img]:rounded-lg",
2432
+ "[&_figure]:my-[1.75em] [&_figure_img]:my-0 [&_figcaption]:mt-2 [&_figcaption]:text-small [&_figcaption]:text-faint-foreground",
2433
+ "[&_table]:my-[1.5em] [&_table]:w-full [&_table]:border-collapse [&_table]:text-small [&_table]:tabular-nums",
2434
+ "[&_th]:border-b [&_th]:border-border-strong [&_th]:px-3 [&_th]:py-2 [&_th]:text-left [&_th]:font-medium",
2435
+ "[&_td]:border-b [&_td]:border-border [&_td]:px-3 [&_td]:py-2 [&_td]:align-top"
2436
+ ] },
2437
+ variants: {
2438
+ size: {
2439
+ sm: { base: "text-small [&_blockquote]:text-body" },
2440
+ md: { base: "text-body [&_blockquote]:text-lead" },
2441
+ lg: { base: "text-lead [&_blockquote]:text-h4" }
2442
+ },
2443
+ fullWidth: {
2444
+ true: { base: "max-w-none" },
2445
+ false: { base: "max-w-prose" }
2446
+ }
2447
+ },
2448
+ defaultVariants: {
2449
+ size: "md",
2450
+ fullWidth: false
2451
+ }
313
2452
  });
314
- //#endregion
315
- //#region src/components/eyebrow/eyebrow.tsx
316
- /** Small uppercase label that sits above a heading. */
317
- function Eyebrow(inProps) {
318
- const [props, slots] = useComponentConfig("Eyebrow", inProps);
319
- const { tone, asChild, className, ...rest } = props;
320
- const s = eyebrowStyles({ tone });
321
- const Comp = asChild ? Slot.Root : "p";
2453
+ /**
2454
+ * Styles raw HTML or MDX (headings, lists, links, quotes, code, tables, images) from theme
2455
+ * tokens. Wrap rendered Markdown or CMS content in it.
2456
+ */
2457
+ function Prose(inProps) {
2458
+ const [props, slots] = useComponentConfig("Prose", inProps);
2459
+ const { size, fullWidth, asChild, className, ...rest } = props;
2460
+ const Comp = asChild ? Slot.Root : "div";
322
2461
  return /* @__PURE__ */ jsx(Comp, {
323
- "data-slot": "eyebrow",
324
- className: s.base({ class: [slots.base, className] }),
2462
+ "data-slot": "prose",
2463
+ className: proseStyles({
2464
+ size,
2465
+ fullWidth
2466
+ }).base({ class: [slots.base, className] }),
325
2467
  ...rest
326
2468
  });
327
2469
  }
328
2470
  //#endregion
329
- //#region src/components/heading/heading.styles.ts
330
- const headingStyles = tv({
331
- slots: { base: "font-display text-balance text-foreground" },
332
- variants: { size: {
333
- display: { base: "text-display" },
334
- h1: { base: "text-h1" },
335
- h2: { base: "text-h2" },
336
- h3: { base: "text-h3" },
337
- h4: { base: "text-h4" }
338
- } }
2471
+ //#region src/components/radio-group/radio-group.styles.ts
2472
+ const control = [
2473
+ "mt-0.5 inline-flex size-4 shrink-0 items-center justify-center rounded-pill border-input bg-surface shadow-xs",
2474
+ themedBorder,
2475
+ transition
2476
+ ];
2477
+ const radioGroupStyles = tv({
2478
+ slots: {
2479
+ root: "",
2480
+ option: "flex items-start gap-2.5",
2481
+ control: [
2482
+ ...control,
2483
+ focusRing,
2484
+ "peer cursor-pointer hover:border-border-strong aria-invalid:border-danger",
2485
+ "data-[state=checked]:border-primary disabled:cursor-not-allowed disabled:opacity-50"
2486
+ ],
2487
+ indicator: "flex size-full items-center justify-center after:block after:size-2 after:rounded-pill after:bg-primary",
2488
+ text: "grid gap-0.5",
2489
+ label: "cursor-pointer text-small font-medium text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-60",
2490
+ description: "text-small text-faint-foreground",
2491
+ card: [
2492
+ "group relative flex w-full cursor-pointer items-start gap-3 rounded-lg border-border bg-surface p-4 text-left shadow-xs",
2493
+ themedBorder,
2494
+ transition,
2495
+ focusRing,
2496
+ "hover:border-border-strong",
2497
+ "data-[state=checked]:border-primary data-[state=checked]:ring-1 data-[state=checked]:ring-primary",
2498
+ "disabled:cursor-not-allowed disabled:opacity-50"
2499
+ ],
2500
+ cardControl: [...control, "group-data-[state=checked]:border-primary"]
2501
+ },
2502
+ variants: {
2503
+ orientation: {
2504
+ vertical: { root: "grid gap-3" },
2505
+ horizontal: { root: "flex flex-wrap gap-x-5 gap-y-3" }
2506
+ },
2507
+ variant: {
2508
+ default: {},
2509
+ card: {}
2510
+ }
2511
+ },
2512
+ compoundVariants: [{
2513
+ variant: "card",
2514
+ orientation: "horizontal",
2515
+ class: { root: "grid grid-cols-[repeat(auto-fit,minmax(12rem,1fr))] gap-3" }
2516
+ }],
2517
+ defaultVariants: {
2518
+ orientation: "vertical",
2519
+ variant: "default"
2520
+ }
339
2521
  });
340
2522
  //#endregion
341
- //#region src/components/heading/heading.tsx
342
- const sizeForLevel = {
343
- 1: "h1",
344
- 2: "h2",
345
- 3: "h3",
346
- 4: "h4",
347
- 5: "h4",
348
- 6: "h4"
349
- };
350
- /** A heading whose semantic level and visual size are set independently. */
351
- function Heading(inProps) {
352
- const [props, slots] = useComponentConfig("Heading", inProps);
353
- const { level = 2, size, asChild, className, ...rest } = props;
354
- const s = headingStyles({ size: size ?? sizeForLevel[level] });
355
- const Comp = asChild ? Slot.Root : `h${level}`;
356
- return /* @__PURE__ */ jsx(Comp, {
357
- "data-slot": "heading",
358
- className: s.base({ class: [slots.base, className] }),
359
- ...rest
2523
+ //#region src/components/radio-group/radio-group.tsx
2524
+ const RadioGroupContext = createContext(null);
2525
+ function useRadioGroupContext() {
2526
+ return useContext(RadioGroupContext) ?? {
2527
+ s: radioGroupStyles(),
2528
+ slots: {},
2529
+ variant: "default"
2530
+ };
2531
+ }
2532
+ /**
2533
+ * Pick exactly one option from a short visible list. `variant="card"` turns each option
2534
+ * into a bordered card with a title and description.
2535
+ */
2536
+ function RadioGroup(inProps) {
2537
+ const [props, slots] = useComponentConfig("RadioGroup", useFieldControl(inProps));
2538
+ const { variant = "default", orientation = "vertical", onValueChange, className, ...rest } = props;
2539
+ const s = radioGroupStyles({
2540
+ variant,
2541
+ orientation
2542
+ });
2543
+ return /* @__PURE__ */ jsx(RadioGroupContext.Provider, {
2544
+ value: {
2545
+ s,
2546
+ slots,
2547
+ variant
2548
+ },
2549
+ children: /* @__PURE__ */ jsx(RadioGroup$1.Root, {
2550
+ "data-slot": "radio-group",
2551
+ "data-variant": variant,
2552
+ orientation,
2553
+ ...onValueChange && { onValueChange: (value) => onValueChange(value) },
2554
+ className: s.root({ class: [slots.root, className] }),
2555
+ ...rest
2556
+ })
2557
+ });
2558
+ }
2559
+ function RadioGroupItem({ label, description, children, className, id, ...props }) {
2560
+ const { s, slots, variant } = useRadioGroupContext();
2561
+ const generated = useId();
2562
+ const itemId = id ?? generated;
2563
+ const descriptionId = description ? `${itemId}-description` : void 0;
2564
+ if (variant === "card") return /* @__PURE__ */ jsxs(RadioGroup$1.Item, {
2565
+ id: itemId,
2566
+ "data-slot": "radio-group-card",
2567
+ "aria-describedby": descriptionId,
2568
+ className: s.card({ class: [slots.card, className] }),
2569
+ ...props,
2570
+ children: [/* @__PURE__ */ jsx("span", {
2571
+ className: s.cardControl({ class: slots.cardControl }),
2572
+ "aria-hidden": "true",
2573
+ children: /* @__PURE__ */ jsx(RadioGroup$1.Indicator, { className: s.indicator({ class: slots.indicator }) })
2574
+ }), /* @__PURE__ */ jsxs("span", {
2575
+ className: s.text({ class: slots.text }),
2576
+ children: [
2577
+ label && /* @__PURE__ */ jsx("span", {
2578
+ className: s.label({ class: slots.label }),
2579
+ children: label
2580
+ }),
2581
+ description && /* @__PURE__ */ jsx("span", {
2582
+ id: descriptionId,
2583
+ className: s.description({ class: slots.description }),
2584
+ children: description
2585
+ }),
2586
+ children
2587
+ ]
2588
+ })]
2589
+ });
2590
+ const control = /* @__PURE__ */ jsx(RadioGroup$1.Item, {
2591
+ id: itemId,
2592
+ "data-slot": "radio-group-item",
2593
+ "aria-describedby": descriptionId,
2594
+ className: s.control({ class: [slots.control, !label && className] }),
2595
+ ...props,
2596
+ children: /* @__PURE__ */ jsx(RadioGroup$1.Indicator, { className: s.indicator({ class: slots.indicator }) })
2597
+ });
2598
+ if (!label) return control;
2599
+ return /* @__PURE__ */ jsxs("div", {
2600
+ "data-slot": "radio-group-option",
2601
+ className: s.option({ class: [slots.option, className] }),
2602
+ children: [control, /* @__PURE__ */ jsxs("span", {
2603
+ className: s.text({ class: slots.text }),
2604
+ children: [/* @__PURE__ */ jsx("label", {
2605
+ htmlFor: itemId,
2606
+ className: s.label({ class: slots.label }),
2607
+ children: label
2608
+ }), description && /* @__PURE__ */ jsx("span", {
2609
+ id: descriptionId,
2610
+ className: s.description({ class: slots.description }),
2611
+ children: description
2612
+ })]
2613
+ })]
360
2614
  });
361
2615
  }
362
2616
  //#endregion
363
- //#region src/components/kbd/kbd.tsx
364
- const kbdStyles = tv({ slots: { base: "inline-flex h-5 min-w-5 items-center justify-center rounded-xs border border-border bg-muted px-1 font-mono text-[0.6875rem] font-medium text-muted-foreground shadow-xs" } });
365
- /** A keyboard key, e.g. `<Kbd>⌘K</Kbd>`. */
366
- function Kbd(inProps) {
367
- const [{ className, ...rest }, slots] = useComponentConfig("Kbd", inProps);
368
- return /* @__PURE__ */ jsx("kbd", {
369
- "data-slot": "kbd",
370
- className: kbdStyles().base({ class: [slots.base, className] }),
371
- ...rest
2617
+ //#region src/components/scroll-area/scroll-area.tsx
2618
+ const scrollAreaStyles = tv({ slots: {
2619
+ root: "relative overflow-hidden",
2620
+ viewport: ["size-full rounded-[inherit]", focusRing],
2621
+ scrollbar: [
2622
+ "flex touch-none select-none p-px transition-colors duration-(--glyph-duration-fast)",
2623
+ "data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-l data-[orientation=vertical]:border-l-transparent",
2624
+ "data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent"
2625
+ ],
2626
+ thumb: "relative flex-1 rounded-pill bg-border-strong hover:bg-faint-foreground",
2627
+ corner: "bg-transparent"
2628
+ } });
2629
+ /**
2630
+ * A scrollable region with slim, theme-colored scrollbars. Give it a height (or width)
2631
+ * with `className`, e.g. `h-72`.
2632
+ */
2633
+ function ScrollArea(inProps) {
2634
+ const [props, slots] = useComponentConfig("ScrollArea", inProps);
2635
+ const { orientation = "vertical", viewportClassName, className, children, ...rest } = props;
2636
+ const s = scrollAreaStyles();
2637
+ const bar = (o) => /* @__PURE__ */ jsx(ScrollArea$1.Scrollbar, {
2638
+ "data-slot": "scroll-area-scrollbar",
2639
+ orientation: o,
2640
+ className: s.scrollbar({ class: slots.scrollbar }),
2641
+ children: /* @__PURE__ */ jsx(ScrollArea$1.Thumb, { className: s.thumb({ class: slots.thumb }) })
2642
+ });
2643
+ return /* @__PURE__ */ jsxs(ScrollArea$1.Root, {
2644
+ "data-slot": "scroll-area",
2645
+ className: s.root({ class: [slots.root, className] }),
2646
+ ...rest,
2647
+ children: [
2648
+ /* @__PURE__ */ jsx(ScrollArea$1.Viewport, {
2649
+ "data-slot": "scroll-area-viewport",
2650
+ className: s.viewport({ class: [slots.viewport, viewportClassName] }),
2651
+ children
2652
+ }),
2653
+ orientation !== "horizontal" && bar("vertical"),
2654
+ orientation !== "vertical" && bar("horizontal"),
2655
+ /* @__PURE__ */ jsx(ScrollArea$1.Corner, { className: s.corner({ class: slots.corner }) })
2656
+ ]
372
2657
  });
373
2658
  }
374
2659
  //#endregion
@@ -532,7 +2817,7 @@ function SelectItem({ className, children, ...props }) {
532
2817
  ...props,
533
2818
  children: [/* @__PURE__ */ jsx(Select$1.ItemText, { children }), /* @__PURE__ */ jsx(Select$1.ItemIndicator, {
534
2819
  className: s.indicator({ class: slots.indicator }),
535
- children: /* @__PURE__ */ jsx(CheckIcon, {})
2820
+ children: /* @__PURE__ */ jsx(CheckIcon$1, {})
536
2821
  })]
537
2822
  });
538
2823
  }
@@ -558,6 +2843,217 @@ function Separator(inProps) {
558
2843
  });
559
2844
  }
560
2845
  //#endregion
2846
+ //#region src/components/sheet/sheet.styles.ts
2847
+ const sheetStyles = tv({
2848
+ slots: {
2849
+ overlay: "fixed inset-0 z-50 animate-fade-in bg-overlay",
2850
+ content: ["fixed z-50 flex flex-col gap-5 border-border bg-surface p-6 text-foreground shadow-lg outline-none", "transition-[translate] duration-(--glyph-duration-slow) ease-standard"],
2851
+ close: [
2852
+ "absolute top-4 right-4 inline-flex size-7 cursor-pointer items-center justify-center rounded-sm text-muted-foreground hover:bg-muted hover:text-foreground [&>svg]:size-4",
2853
+ transition,
2854
+ focusRing
2855
+ ],
2856
+ header: "flex flex-col gap-1.5 pr-8",
2857
+ title: "font-display text-h4 text-foreground",
2858
+ description: "text-small text-muted-foreground",
2859
+ body: "-mx-6 min-h-0 flex-1 overflow-y-auto px-6 text-small",
2860
+ footer: "mt-auto flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"
2861
+ },
2862
+ variants: {
2863
+ side: {
2864
+ right: { content: "inset-y-0 right-0 h-full w-full border-l-(length:--glyph-border-width) starting:translate-x-full" },
2865
+ left: { content: "inset-y-0 left-0 h-full w-full border-r-(length:--glyph-border-width) starting:-translate-x-full" },
2866
+ top: { content: "inset-x-0 top-0 max-h-[85dvh] border-b-(length:--glyph-border-width) starting:-translate-y-full" },
2867
+ bottom: { content: "inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl border-t-(length:--glyph-border-width) starting:translate-y-full" }
2868
+ },
2869
+ size: {
2870
+ sm: {},
2871
+ md: {},
2872
+ lg: {},
2873
+ xl: {}
2874
+ }
2875
+ },
2876
+ compoundVariants: [
2877
+ {
2878
+ side: ["left", "right"],
2879
+ size: "sm",
2880
+ class: { content: "sm:max-w-sm" }
2881
+ },
2882
+ {
2883
+ side: ["left", "right"],
2884
+ size: "md",
2885
+ class: { content: "sm:max-w-md" }
2886
+ },
2887
+ {
2888
+ side: ["left", "right"],
2889
+ size: "lg",
2890
+ class: { content: "sm:max-w-xl" }
2891
+ },
2892
+ {
2893
+ side: ["left", "right"],
2894
+ size: "xl",
2895
+ class: { content: "sm:max-w-3xl" }
2896
+ }
2897
+ ],
2898
+ defaultVariants: {
2899
+ side: "right",
2900
+ size: "md"
2901
+ }
2902
+ });
2903
+ //#endregion
2904
+ //#region src/components/sheet/sheet.tsx
2905
+ function useParts() {
2906
+ const [, slots] = useComponentConfig("Sheet", {});
2907
+ return {
2908
+ s: sheetStyles(),
2909
+ slots
2910
+ };
2911
+ }
2912
+ /** A panel that slides in from an edge: filters, details, settings, mobile navigation. */
2913
+ const Sheet = Dialog$1.Root;
2914
+ const SheetTrigger = Dialog$1.Trigger;
2915
+ const SheetClose = Dialog$1.Close;
2916
+ function SheetContent(inProps) {
2917
+ const [props, slots] = useComponentConfig("Sheet", inProps);
2918
+ const { side, size, showClose = true, overlayClassName, className, children, ...rest } = props;
2919
+ const s = sheetStyles({
2920
+ side,
2921
+ size
2922
+ });
2923
+ return /* @__PURE__ */ jsxs(Dialog$1.Portal, { children: [/* @__PURE__ */ jsx(Dialog$1.Overlay, {
2924
+ "data-slot": "sheet-overlay",
2925
+ className: s.overlay({ class: [slots.overlay, overlayClassName] })
2926
+ }), /* @__PURE__ */ jsxs(Dialog$1.Content, {
2927
+ "data-slot": "sheet-content",
2928
+ "data-side": side ?? "right",
2929
+ className: s.content({ class: [slots.content, className] }),
2930
+ ...rest,
2931
+ children: [children, showClose && /* @__PURE__ */ jsx(Dialog$1.Close, {
2932
+ "data-slot": "sheet-close",
2933
+ "aria-label": "Close",
2934
+ className: s.close({ class: slots.close }),
2935
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
2936
+ })]
2937
+ })] });
2938
+ }
2939
+ function SheetHeader({ className, ...props }) {
2940
+ const { s, slots } = useParts();
2941
+ return /* @__PURE__ */ jsx("div", {
2942
+ "data-slot": "sheet-header",
2943
+ className: s.header({ class: [slots.header, className] }),
2944
+ ...props
2945
+ });
2946
+ }
2947
+ function SheetTitle({ className, ...props }) {
2948
+ const { s, slots } = useParts();
2949
+ return /* @__PURE__ */ jsx(Dialog$1.Title, {
2950
+ "data-slot": "sheet-title",
2951
+ className: s.title({ class: [slots.title, className] }),
2952
+ ...props
2953
+ });
2954
+ }
2955
+ function SheetDescription({ className, ...props }) {
2956
+ const { s, slots } = useParts();
2957
+ return /* @__PURE__ */ jsx(Dialog$1.Description, {
2958
+ "data-slot": "sheet-description",
2959
+ className: s.description({ class: [slots.description, className] }),
2960
+ ...props
2961
+ });
2962
+ }
2963
+ function SheetBody({ className, ...props }) {
2964
+ const { s, slots } = useParts();
2965
+ return /* @__PURE__ */ jsx("div", {
2966
+ "data-slot": "sheet-body",
2967
+ className: s.body({ class: [slots.body, className] }),
2968
+ ...props
2969
+ });
2970
+ }
2971
+ function SheetFooter({ className, ...props }) {
2972
+ const { s, slots } = useParts();
2973
+ return /* @__PURE__ */ jsx("div", {
2974
+ "data-slot": "sheet-footer",
2975
+ className: s.footer({ class: [slots.footer, className] }),
2976
+ ...props
2977
+ });
2978
+ }
2979
+ //#endregion
2980
+ //#region src/components/slider/slider.styles.ts
2981
+ const sliderStyles = tv({
2982
+ slots: {
2983
+ wrapper: "grid w-full gap-1.5",
2984
+ root: "relative flex h-5 w-full touch-none select-none items-center data-disabled:cursor-not-allowed data-disabled:opacity-50",
2985
+ track: "relative h-1.5 w-full grow overflow-hidden rounded-pill bg-muted",
2986
+ range: "absolute h-full bg-primary",
2987
+ thumb: [
2988
+ "relative block size-4 cursor-grab rounded-pill border-2 border-primary bg-background shadow-sm outline-none active:cursor-grabbing",
2989
+ "transition-[box-shadow] duration-(--glyph-duration-fast) ease-standard",
2990
+ "hover:ring-4 hover:ring-ring/15 focus-visible:ring-4 focus-visible:ring-ring/30",
2991
+ "data-disabled:cursor-not-allowed"
2992
+ ],
2993
+ value: "pointer-events-none absolute bottom-full left-1/2 mb-2 -translate-x-1/2 whitespace-nowrap rounded-xs bg-secondary px-1.5 py-0.5 font-mono text-caption text-secondary-foreground tabular-nums",
2994
+ marks: "relative h-4 w-full",
2995
+ mark: "absolute top-0 -translate-x-1/2 text-caption text-faint-foreground tabular-nums"
2996
+ },
2997
+ variants: { showValue: { true: { wrapper: "pt-7" } } }
2998
+ });
2999
+ //#endregion
3000
+ //#region src/components/slider/slider.tsx
3001
+ const toArray = (value) => value === void 0 ? void 0 : typeof value === "number" ? [value] : [...value];
3002
+ /** Choose a number, or a range with two thumbs, by dragging or with arrow keys. */
3003
+ function Slider(inProps) {
3004
+ const [props, slots] = useComponentConfig("Slider", useFieldControl(inProps));
3005
+ const { value, defaultValue, onValueChange, onValueCommit, min = 0, max = 100, step = 1, minStepsBetweenThumbs, marks, showValue = false, disabled, name, id, className, thumbLabels = ["Minimum", "Maximum"], "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid } = props;
3006
+ const isRange = Array.isArray(value ?? defaultValue);
3007
+ const fromArray = (next) => isRange ? [next[0], next[1]] : next[0];
3008
+ const current = toArray(value) ?? toArray(defaultValue) ?? [min];
3009
+ const s = sliderStyles({ showValue: Boolean(showValue) });
3010
+ const format = typeof showValue === "function" ? showValue : (n) => n;
3011
+ return /* @__PURE__ */ jsxs("div", {
3012
+ "data-slot": "slider",
3013
+ className: s.wrapper({ class: [slots.wrapper, className] }),
3014
+ children: [/* @__PURE__ */ jsxs(Slider$1.Root, {
3015
+ className: s.root({ class: slots.root }),
3016
+ min,
3017
+ max,
3018
+ step,
3019
+ disabled,
3020
+ name,
3021
+ ...minStepsBetweenThumbs !== void 0 && { minStepsBetweenThumbs },
3022
+ ...value !== void 0 && { value: toArray(value) },
3023
+ ...defaultValue !== void 0 && { defaultValue: toArray(defaultValue) },
3024
+ ...onValueChange && { onValueChange: (next) => onValueChange(fromArray(next)) },
3025
+ ...onValueCommit && { onValueCommit: (next) => onValueCommit(fromArray(next)) },
3026
+ children: [/* @__PURE__ */ jsx(Slider$1.Track, {
3027
+ className: s.track({ class: slots.track }),
3028
+ children: /* @__PURE__ */ jsx(Slider$1.Range, { className: s.range({ class: slots.range }) })
3029
+ }), current.map((thumbValue, index) => /* @__PURE__ */ jsx(Slider$1.Thumb, {
3030
+ id: index === 0 ? id : void 0,
3031
+ "aria-label": isRange ? thumbLabels[index] : ariaLabel,
3032
+ "aria-describedby": ariaDescribedBy,
3033
+ "aria-invalid": ariaInvalid,
3034
+ className: s.thumb({ class: slots.thumb }),
3035
+ children: showValue && /* @__PURE__ */ jsx("span", {
3036
+ className: s.value({ class: slots.value }),
3037
+ "aria-hidden": "true",
3038
+ children: format(thumbValue)
3039
+ })
3040
+ }, index))]
3041
+ }), marks && marks.length > 0 && /* @__PURE__ */ jsx("div", {
3042
+ className: s.marks({ class: slots.marks }),
3043
+ "aria-hidden": "true",
3044
+ children: marks.map((mark) => {
3045
+ const m = typeof mark === "number" ? { value: mark } : mark;
3046
+ const percent = (m.value - min) / (max - min || 1) * 100;
3047
+ return /* @__PURE__ */ jsx("span", {
3048
+ className: s.mark({ class: slots.mark }),
3049
+ style: { left: `${percent}%` },
3050
+ children: m.label ?? m.value
3051
+ }, m.value);
3052
+ })
3053
+ })]
3054
+ });
3055
+ }
3056
+ //#endregion
561
3057
  //#region src/components/stack/stack.tsx
562
3058
  const stackStyles = tv({
563
3059
  base: "flex",
@@ -615,6 +3111,94 @@ function Stack({ direction, gap, align, justify, wrap, asChild, className, ...pr
615
3111
  });
616
3112
  }
617
3113
  //#endregion
3114
+ //#region src/components/stat-card/stat-card.styles.ts
3115
+ const statCardStyles = tv({ slots: {
3116
+ root: "gap-2",
3117
+ header: "flex items-center justify-between gap-2",
3118
+ label: "text-small text-muted-foreground",
3119
+ icon: "flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground [&>svg]:size-4",
3120
+ valueRow: "flex flex-wrap items-baseline gap-x-2 gap-y-1",
3121
+ value: "font-display text-h2 tabular-nums text-foreground",
3122
+ delta: "gap-1 [&>svg]:size-3",
3123
+ description: "text-small text-faint-foreground",
3124
+ chart: "mt-1 min-w-0 text-primary"
3125
+ } });
3126
+ //#endregion
3127
+ //#region src/components/stat-card/stat-card.tsx
3128
+ const ArrowUp = () => /* @__PURE__ */ jsx("svg", {
3129
+ viewBox: "0 0 24 24",
3130
+ fill: "none",
3131
+ stroke: "currentColor",
3132
+ strokeWidth: "2.5",
3133
+ strokeLinecap: "round",
3134
+ strokeLinejoin: "round",
3135
+ "aria-hidden": "true",
3136
+ children: /* @__PURE__ */ jsx("path", { d: "M7 17 17 7M8 7h9v9" })
3137
+ });
3138
+ const ArrowDown = () => /* @__PURE__ */ jsx("svg", {
3139
+ viewBox: "0 0 24 24",
3140
+ fill: "none",
3141
+ stroke: "currentColor",
3142
+ strokeWidth: "2.5",
3143
+ strokeLinecap: "round",
3144
+ strokeLinejoin: "round",
3145
+ "aria-hidden": "true",
3146
+ children: /* @__PURE__ */ jsx("path", { d: "M7 7l10 10M17 8v9H8" })
3147
+ });
3148
+ function deltaTone(trend, invert) {
3149
+ if (trend === "neutral") return "neutral";
3150
+ return trend === "up" !== invert ? "success" : "danger";
3151
+ }
3152
+ /** A key metric with its label, change versus the last period, and an optional chart. */
3153
+ function StatCard(inProps) {
3154
+ const [props, slots] = useComponentConfig("StatCard", inProps);
3155
+ const { label, value, delta, trend = "neutral", invertTrend = false, icon, description, chart, className, ...cardProps } = props;
3156
+ const s = statCardStyles();
3157
+ return /* @__PURE__ */ jsxs(Card, {
3158
+ "data-slot": "stat-card",
3159
+ className: s.root({ class: [slots.root, className] }),
3160
+ ...cardProps,
3161
+ children: [
3162
+ /* @__PURE__ */ jsxs("div", {
3163
+ className: s.header({ class: slots.header }),
3164
+ children: [/* @__PURE__ */ jsx("p", {
3165
+ className: s.label({ class: slots.label }),
3166
+ children: label
3167
+ }), icon && /* @__PURE__ */ jsx("span", {
3168
+ className: s.icon({ class: slots.icon }),
3169
+ "aria-hidden": "true",
3170
+ children: icon
3171
+ })]
3172
+ }),
3173
+ /* @__PURE__ */ jsxs("div", {
3174
+ className: s.valueRow({ class: slots.valueRow }),
3175
+ children: [/* @__PURE__ */ jsx("p", {
3176
+ "data-slot": "stat-card-value",
3177
+ className: s.value({ class: slots.value }),
3178
+ children: value
3179
+ }), delta !== void 0 && /* @__PURE__ */ jsxs(Badge, {
3180
+ "data-trend": trend,
3181
+ tone: deltaTone(trend, invertTrend),
3182
+ className: s.delta({ class: slots.delta }),
3183
+ children: [
3184
+ trend === "up" && /* @__PURE__ */ jsx(ArrowUp, {}),
3185
+ trend === "down" && /* @__PURE__ */ jsx(ArrowDown, {}),
3186
+ delta
3187
+ ]
3188
+ })]
3189
+ }),
3190
+ description && /* @__PURE__ */ jsx("p", {
3191
+ className: s.description({ class: slots.description }),
3192
+ children: description
3193
+ }),
3194
+ chart && /* @__PURE__ */ jsx("div", {
3195
+ className: s.chart({ class: slots.chart }),
3196
+ children: chart
3197
+ })
3198
+ ]
3199
+ });
3200
+ }
3201
+ //#endregion
618
3202
  //#region src/components/switch/switch.tsx
619
3203
  const switchStyles = tv({
620
3204
  slots: {
@@ -789,6 +3373,74 @@ function Textarea(inProps) {
789
3373
  });
790
3374
  }
791
3375
  //#endregion
3376
+ //#region src/components/toast/toast.tsx
3377
+ const toastStyles = tv({ slots: {
3378
+ toast: ["group flex w-(--width) items-start gap-3 rounded-lg border-border bg-raised p-4 text-small text-foreground shadow-lg", themedBorder],
3379
+ content: "flex min-w-0 flex-1 flex-col gap-0.5",
3380
+ title: "font-medium text-foreground",
3381
+ description: "text-muted-foreground",
3382
+ icon: "mt-0.5 flex size-4 shrink-0 items-center justify-center [&>svg]:size-4",
3383
+ actionButton: [
3384
+ "inline-flex h-7 shrink-0 cursor-pointer items-center rounded-sm bg-primary px-2.5 text-caption font-medium text-primary-foreground hover:bg-primary/88",
3385
+ transition,
3386
+ focusRing
3387
+ ],
3388
+ cancelButton: [
3389
+ "inline-flex h-7 shrink-0 cursor-pointer items-center rounded-sm bg-muted px-2.5 text-caption font-medium text-muted-foreground hover:text-foreground",
3390
+ transition,
3391
+ focusRing
3392
+ ],
3393
+ closeButton: [
3394
+ "absolute -top-2 -left-2 flex size-5 cursor-pointer items-center justify-center rounded-pill border-border bg-raised text-muted-foreground shadow-xs hover:text-foreground [&>svg]:size-3",
3395
+ themedBorder,
3396
+ focusRing
3397
+ ],
3398
+ success: "[&_[data-icon]]:text-success",
3399
+ error: "[&_[data-icon]]:text-danger",
3400
+ warning: "[&_[data-icon]]:text-warning",
3401
+ info: "[&_[data-icon]]:text-info",
3402
+ loading: "[&_[data-icon]]:text-muted-foreground"
3403
+ } });
3404
+ /**
3405
+ * Renders toasts sent with `toast()`. Mount once near the root. Styled entirely by the
3406
+ * theme's tokens, so it follows the theme and color mode automatically.
3407
+ *
3408
+ * ```tsx
3409
+ * toast.success('Saved')
3410
+ * toast.promise(save(), { loading: 'Saving…', success: 'Saved', error: 'Couldn’t save' })
3411
+ * ```
3412
+ */
3413
+ function Toaster(inProps) {
3414
+ const [props, slots] = useComponentConfig("Toast", inProps);
3415
+ const { toastOptions, position = "bottom-right", ...rest } = props;
3416
+ const s = toastStyles();
3417
+ const classNames = toastOptions?.classNames ?? {};
3418
+ return /* @__PURE__ */ jsx(Toaster$1, {
3419
+ position,
3420
+ gap: 10,
3421
+ ...rest,
3422
+ toastOptions: {
3423
+ ...toastOptions,
3424
+ unstyled: true,
3425
+ classNames: {
3426
+ toast: s.toast({ class: [slots.toast, classNames.toast] }),
3427
+ content: s.content({ class: [slots.content, classNames.content] }),
3428
+ title: s.title({ class: [slots.title, classNames.title] }),
3429
+ description: s.description({ class: [slots.description, classNames.description] }),
3430
+ icon: s.icon({ class: [slots.icon, classNames.icon] }),
3431
+ actionButton: s.actionButton({ class: [slots.actionButton, classNames.actionButton] }),
3432
+ cancelButton: s.cancelButton({ class: [slots.cancelButton, classNames.cancelButton] }),
3433
+ closeButton: s.closeButton({ class: [slots.closeButton, classNames.closeButton] }),
3434
+ success: s.success({ class: [slots.success, classNames.success] }),
3435
+ error: s.error({ class: [slots.error, classNames.error] }),
3436
+ warning: s.warning({ class: [slots.warning, classNames.warning] }),
3437
+ info: s.info({ class: [slots.info, classNames.info] }),
3438
+ loading: s.loading({ class: [slots.loading, classNames.loading] })
3439
+ }
3440
+ }
3441
+ });
3442
+ }
3443
+ //#endregion
792
3444
  //#region src/components/tooltip/tooltip.tsx
793
3445
  const tooltipStyles = tv({ slots: { content: "z-50 max-w-xs animate-pop-in rounded-sm bg-secondary px-2 py-1 text-caption text-secondary-foreground shadow-md" } });
794
3446
  /** A short hint on hover or focus. The child must be focusable (a button or link). */
@@ -811,21 +3463,6 @@ function Tooltip(inProps) {
811
3463
  });
812
3464
  }
813
3465
  //#endregion
814
- //#region src/hooks/use-controllable-state.ts
815
- /** State that can be controlled by a parent (`value` + `onChange`) or left uncontrolled. */
816
- function useControllableState({ value, defaultValue, onChange }) {
817
- const [internal, setInternal] = useState(defaultValue);
818
- const isControlled = value !== void 0;
819
- const current = isControlled ? value : internal;
820
- const onChangeRef = useRef(onChange);
821
- onChangeRef.current = onChange;
822
- return [current, useCallback((next) => {
823
- const resolved = typeof next === "function" ? next(current) : next;
824
- if (!isControlled) setInternal(resolved);
825
- onChangeRef.current?.(resolved);
826
- }, [current, isControlled])];
827
- }
828
- //#endregion
829
3466
  //#region src/hooks/use-media-query.ts
830
3467
  /** Subscribes to a CSS media query. Returns `fallback` during SSR. */
831
3468
  function useMediaQuery(query, fallback = false) {
@@ -1121,13 +3758,13 @@ function AppShell(inProps) {
1121
3758
  className: s.sidebar({ class: slots.sidebar }),
1122
3759
  children: sidebar
1123
3760
  }),
1124
- /* @__PURE__ */ jsx(Dialog.Root, {
3761
+ /* @__PURE__ */ jsx(Dialog$1.Root, {
1125
3762
  open: mobileOpen,
1126
3763
  onOpenChange: setMobileOpen,
1127
- children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: s.overlay({ class: slots.overlay }) }), /* @__PURE__ */ jsxs(Dialog.Content, {
3764
+ children: /* @__PURE__ */ jsxs(Dialog$1.Portal, { children: [/* @__PURE__ */ jsx(Dialog$1.Overlay, { className: s.overlay({ class: slots.overlay }) }), /* @__PURE__ */ jsxs(Dialog$1.Content, {
1128
3765
  className: s.drawer({ class: slots.drawer }),
1129
3766
  "aria-describedby": void 0,
1130
- children: [/* @__PURE__ */ jsx(Dialog.Title, {
3767
+ children: [/* @__PURE__ */ jsx(Dialog$1.Title, {
1131
3768
  className: "sr-only",
1132
3769
  children: "Navigation"
1133
3770
  }), /* @__PURE__ */ jsx(AppShellContext.Provider, {
@@ -1191,29 +3828,29 @@ function Navbar(inProps) {
1191
3828
  className: s.actions({ class: slots.actions }),
1192
3829
  children: actions
1193
3830
  }),
1194
- /* @__PURE__ */ jsxs(Dialog.Root, {
3831
+ /* @__PURE__ */ jsxs(Dialog$1.Root, {
1195
3832
  open,
1196
3833
  onOpenChange: setOpen,
1197
- children: [/* @__PURE__ */ jsx(Dialog.Trigger, {
3834
+ children: [/* @__PURE__ */ jsx(Dialog$1.Trigger, {
1198
3835
  asChild: true,
1199
3836
  children: /* @__PURE__ */ jsx(IconButton, {
1200
3837
  icon: /* @__PURE__ */ jsx(MenuIcon, {}),
1201
3838
  "aria-label": "Open menu",
1202
3839
  className: s.menuButton({ class: slots.menuButton })
1203
3840
  })
1204
- }), /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: s.overlay({ class: slots.overlay }) }), /* @__PURE__ */ jsxs(Dialog.Content, {
3841
+ }), /* @__PURE__ */ jsxs(Dialog$1.Portal, { children: [/* @__PURE__ */ jsx(Dialog$1.Overlay, { className: s.overlay({ class: slots.overlay }) }), /* @__PURE__ */ jsxs(Dialog$1.Content, {
1205
3842
  className: s.panel({ class: slots.panel }),
1206
3843
  "aria-describedby": void 0,
1207
3844
  children: [
1208
3845
  /* @__PURE__ */ jsxs("div", {
1209
3846
  className: s.panelHeader({ class: slots.panelHeader }),
1210
- children: [/* @__PURE__ */ jsx(Dialog.Title, {
3847
+ children: [/* @__PURE__ */ jsx(Dialog$1.Title, {
1211
3848
  asChild: true,
1212
3849
  children: /* @__PURE__ */ jsx("div", {
1213
3850
  className: s.brand({ class: slots.brand }),
1214
3851
  children: brand
1215
3852
  })
1216
- }), /* @__PURE__ */ jsx(Dialog.Close, {
3853
+ }), /* @__PURE__ */ jsx(Dialog$1.Close, {
1217
3854
  asChild: true,
1218
3855
  children: /* @__PURE__ */ jsx(IconButton, {
1219
3856
  icon: /* @__PURE__ */ jsx(XIcon, {}),
@@ -1476,8 +4113,8 @@ function ThemeStyle({ theme, selector }) {
1476
4113
  }
1477
4114
  //#endregion
1478
4115
  //#region src/provider/glyph-provider.tsx
1479
- /** Provides the theme, color mode and app settings. Render once at the root. */
1480
- function GlyphProvider({ children, theme = glyph, defaultMode, storageKey, linkComponent = "a" }) {
4116
+ /** Provides the theme, color mode, tooltips, `useConfirm()` and (optionally) toasts. Render once at the root. */
4117
+ function GlyphProvider({ children, theme = glyph, defaultMode, storageKey, linkComponent = "a", toaster = false }) {
1481
4118
  const value = useMemo(() => ({
1482
4119
  theme,
1483
4120
  linkComponent
@@ -1489,7 +4126,7 @@ function GlyphProvider({ children, theme = glyph, defaultMode, storageKey, linkC
1489
4126
  value,
1490
4127
  children: [/* @__PURE__ */ jsx(ThemeStyle, { theme }), /* @__PURE__ */ jsx(Tooltip$1.Provider, {
1491
4128
  delayDuration: 300,
1492
- children
4129
+ children: /* @__PURE__ */ jsxs(ConfirmProvider, { children: [children, toaster && /* @__PURE__ */ jsx(Toaster, { ...toaster === true ? {} : toaster })] })
1493
4130
  })]
1494
4131
  })
1495
4132
  });
@@ -1526,4 +4163,4 @@ function ThemeScope({ theme, mode, asChild, children, ...props }) {
1526
4163
  });
1527
4164
  }
1528
4165
  //#endregion
1529
- export { AppShell, Async, Avatar, AvatarGroup, Badge, Button, Card, CardBody, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, ColorModeProvider, ColorModeScript, Container, EmptyState, ErrorState, Eyebrow, Field, FieldContext, GlyphProvider, Heading, IconButton, Input, Kbd, Label, LoadingState, Navbar, PageHeader, Section, SegmentedControl, Select, SelectItem, Separator, Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarItem, SidebarSection, SidebarTrigger, Skeleton, Spinner, Stack, Switch, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, Textarea, ThemeScope, Tooltip, appShellStyles, avatarStyles, badgeStyles, brutalist, buttonStyles, cardStyles, checkboxStyles, cn, containerStyles, defineTheme, editorial, eyebrowStyles, fieldControl, fieldStyles, getColorModeScript, glyph, headingStyles, inputStyles, kbdStyles, labelStyles, navbarStyles, pageHeaderStyles, playful, presets, sectionStyles, segmentedControlStyles, selectStyles, separatorStyles, sidebarStyles, skeletonStyles, spinnerStyles, stackStyles, stateStyles, switchStyles, tableStyles, tabsStyles, textStyles, textareaStyles, themeToCss, tokenVar, tooltipStyles, tv, useAppShell, useAsync, useColorMode, useComponentConfig, useControllableState, useFieldControl, useGlyph, useLinkComponent, useMediaQuery, useScrolled };
4166
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, AppShell, AspectRatio, Async, Avatar, AvatarGroup, Badge, Banner, Blockquote, Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Card, CardBody, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Code, CodeBlock, ColorModeProvider, ColorModeScript, Combobox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandMenu, CommandSeparator, ConfirmProvider, Container, DescriptionItem, DescriptionList, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ErrorState, Eyebrow, Field, FieldContext, GlyphProvider, Grid, Heading, IconButton, Input, Kbd, Label, Link, LoadingState, Navbar, PageHeader, Pagination, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, ProgressCircle, Prose, RadioGroup, RadioGroupItem, ScrollArea, Section, SegmentedControl, Select, SelectItem, Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarItem, SidebarSection, SidebarTrigger, Skeleton, Slider, Spinner, Stack, StatCard, Switch, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, Textarea, ThemeScope, Toaster, Tooltip, accordionStyles, alertDialogStyles, alertStyles, appShellStyles, aspectRatioStyles, avatarStyles, badgeStyles, bannerStyles, blockquoteStyles, breadcrumbStyles, brutalist, buttonStyles, cardStyles, checkboxStyles, cn, codeBlockStyles, codeStyles, comboboxStyles, commandMenuStyles, containerStyles, defineTheme, descriptionListStyles, dialogStyles, dropdownMenuStyles, editorial, eyebrowStyles, fieldControl, fieldStyles, getColorModeScript, glyph, gridStyles, headingStyles, inputStyles, kbdStyles, labelStyles, linkStyles, navbarStyles, pageHeaderStyles, paginationRange, paginationStyles, playful, popoverStyles, presets, progressCircleStyles, progressStyles, proseStyles, radioGroupStyles, scrollAreaStyles, sectionStyles, segmentedControlStyles, selectStyles, separatorStyles, sheetStyles, sidebarStyles, skeletonStyles, sliderStyles, spinnerStyles, stackStyles, statCardStyles, stateStyles, switchStyles, tableStyles, tabsStyles, textStyles, textareaStyles, themeToCss, toast, toastStyles, tokenVar, tooltipStyles, tv, useAppShell, useAsync, useColorMode, useCommandMenuShortcut, useComponentConfig, useConfirm, useControllableState, useFieldControl, useGlyph, useLinkComponent, useMediaQuery, useScrolled };