@xenide-io/the-old-ui-theme 0.5.4 → 0.6.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 (63) hide show
  1. package/dist/{Chip-C5hRFAhe.d.mts → Chip-DzC5xtK9.d.mts} +8 -3
  2. package/dist/{Chip-C5hRFAhe.d.ts → Chip-DzC5xtK9.d.ts} +8 -3
  3. package/dist/chunk-3G43JEI3.mjs +2564 -0
  4. package/dist/index.d.mts +2 -2
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +7 -2
  7. package/dist/index.mjs +3 -1
  8. package/dist/tailwind-preset.js +1 -0
  9. package/dist/tailwind-preset.mjs +1 -0
  10. package/dist/ui.d.mts +4 -531
  11. package/dist/ui.d.ts +4 -531
  12. package/dist/ui.js +407 -2504
  13. package/dist/ui.mjs +5 -91
  14. package/package.json +1 -1
  15. package/src/app/globals.css +18 -0
  16. package/src/components/ui/Typography.tsx +12 -4
  17. package/src/components/ui/index.ts +7 -184
  18. package/src/components/ui/typography.test.tsx +27 -0
  19. package/src/styles/suite-skin.css +21 -1
  20. package/src/styles/typography.css +72 -3
  21. package/tailwind-preset.ts +1 -0
  22. package/dist/chunk-SBBKXV35.mjs +0 -4620
  23. package/src/components/ui/AlertDialog.tsx +0 -62
  24. package/src/components/ui/AppLayout.tsx +0 -27
  25. package/src/components/ui/Autocomplete.tsx +0 -106
  26. package/src/components/ui/Banner.tsx +0 -63
  27. package/src/components/ui/ButtonGroup.tsx +0 -16
  28. package/src/components/ui/ChatBubble.tsx +0 -71
  29. package/src/components/ui/Collapsible.tsx +0 -46
  30. package/src/components/ui/Combobox.tsx +0 -119
  31. package/src/components/ui/ContextMenu.tsx +0 -81
  32. package/src/components/ui/DataTable.tsx +0 -133
  33. package/src/components/ui/DatePicker.tsx +0 -96
  34. package/src/components/ui/Dialog.tsx +0 -75
  35. package/src/components/ui/Divider.tsx +0 -39
  36. package/src/components/ui/Drawer.tsx +0 -71
  37. package/src/components/ui/HoverCard.tsx +0 -36
  38. package/src/components/ui/Indicator.tsx +0 -61
  39. package/src/components/ui/InputGroup.tsx +0 -16
  40. package/src/components/ui/Lettermark.tsx +0 -47
  41. package/src/components/ui/LoadingBar.tsx +0 -25
  42. package/src/components/ui/Menubar.tsx +0 -66
  43. package/src/components/ui/Metric.tsx +0 -34
  44. package/src/components/ui/Navigation.tsx +0 -94
  45. package/src/components/ui/NumberField.tsx +0 -76
  46. package/src/components/ui/Popover.tsx +0 -73
  47. package/src/components/ui/ProgressCircle.tsx +0 -63
  48. package/src/components/ui/Rating.tsx +0 -65
  49. package/src/components/ui/Resizable.tsx +0 -71
  50. package/src/components/ui/Row.tsx +0 -51
  51. package/src/components/ui/ScrollArea.tsx +0 -54
  52. package/src/components/ui/Sidebar.tsx +0 -79
  53. package/src/components/ui/Snack.tsx +0 -48
  54. package/src/components/ui/Splotch.tsx +0 -33
  55. package/src/components/ui/Stepper.tsx +0 -74
  56. package/src/components/ui/Tabs.tsx +0 -53
  57. package/src/components/ui/Tag.tsx +0 -65
  58. package/src/components/ui/Terminal.tsx +0 -54
  59. package/src/components/ui/ThemeManager.tsx +0 -18
  60. package/src/components/ui/Timeline.tsx +0 -60
  61. package/src/components/ui/Toast.tsx +0 -70
  62. package/src/components/ui/Toggle.tsx +0 -62
  63. package/src/components/ui/Widget.tsx +0 -31
@@ -0,0 +1,2564 @@
1
+ import {
2
+ ButtonChrome,
3
+ DropdownMenu,
4
+ DropdownRadioGroup,
5
+ DropdownRadioItem,
6
+ IconArrowDown,
7
+ IconCancel,
8
+ IconCheck,
9
+ IconCheckCircle,
10
+ IconChevronDown,
11
+ IconChevronLeft,
12
+ IconChevronRight,
13
+ IconClose,
14
+ IconCodePreview,
15
+ IconExclamation,
16
+ IconInfo,
17
+ IconSearch,
18
+ IconTuning,
19
+ cn
20
+ } from "./chunk-E5ZBQYEX.mjs";
21
+ import {
22
+ __objRest,
23
+ __spreadProps,
24
+ __spreadValues
25
+ } from "./chunk-FWCSY2DS.mjs";
26
+
27
+ // src/components/ui/Button.tsx
28
+ import { forwardRef } from "react";
29
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
30
+ var variantClass = {
31
+ primary: "ph-btn-primary",
32
+ secondary: "ph-btn-secondary",
33
+ tertiary: "ph-btn-tertiary",
34
+ signal: "ph-btn-signal",
35
+ accent: "ph-btn-accent",
36
+ neutral: "ph-btn-neutral",
37
+ info: "ph-btn-info",
38
+ success: "ph-btn-success",
39
+ warning: "ph-btn-warning",
40
+ danger: "ph-btn-danger",
41
+ ghost: "ph-btn-ghost",
42
+ link: "ph-btn-link"
43
+ };
44
+ var sizeClass = {
45
+ xs: "ph-btn-xs",
46
+ sm: "ph-btn-sm",
47
+ md: "",
48
+ lg: "ph-btn-lg"
49
+ };
50
+ var shapeClass = {
51
+ default: "",
52
+ circle: "ph-btn-circle",
53
+ square: "ph-btn-square",
54
+ wide: "ph-btn-wide"
55
+ };
56
+ var Button = forwardRef(function Button2(_a, ref) {
57
+ var _b = _a, {
58
+ variant = "secondary",
59
+ size = "md",
60
+ shape = "default",
61
+ outline = false,
62
+ split = false,
63
+ icon,
64
+ sideIcon,
65
+ loading = false,
66
+ loadingLabel,
67
+ className,
68
+ children,
69
+ type = "button",
70
+ disabled
71
+ } = _b, props = __objRest(_b, [
72
+ "variant",
73
+ "size",
74
+ "shape",
75
+ "outline",
76
+ "split",
77
+ "icon",
78
+ "sideIcon",
79
+ "loading",
80
+ "loadingLabel",
81
+ "className",
82
+ "children",
83
+ "type",
84
+ "disabled"
85
+ ]);
86
+ const usesLemonChrome = !["tertiary", "ghost", "link"].includes(variant);
87
+ const label = loadingLabel != null ? loadingLabel : children;
88
+ const leadingIcon = loading ? /* @__PURE__ */ jsx("span", { className: "ph-btn-spinner", "aria-hidden": true }) : icon;
89
+ const content = usesLemonChrome ? /* @__PURE__ */ jsx(ButtonChrome, { label, icon: leadingIcon, sideIcon, split }) : /* @__PURE__ */ jsxs(Fragment, { children: [
90
+ leadingIcon != null ? /* @__PURE__ */ jsx("span", { className: "ph-btn-icon", children: leadingIcon }) : null,
91
+ label != null ? /* @__PURE__ */ jsx("span", { className: "ph-btn-label", children: label }) : null,
92
+ split ? /* @__PURE__ */ jsx("span", { className: "ph-btn-split-divider", "aria-hidden": true }) : null,
93
+ sideIcon != null ? /* @__PURE__ */ jsx("span", { className: "ph-btn-side-icon", children: sideIcon }) : null
94
+ ] });
95
+ return /* @__PURE__ */ jsx(
96
+ "button",
97
+ __spreadProps(__spreadValues({
98
+ ref,
99
+ type,
100
+ disabled: disabled || loading,
101
+ "aria-busy": loading || void 0,
102
+ className: cn(
103
+ "ph-btn",
104
+ usesLemonChrome && "ph-btn-raised",
105
+ outline && "ph-btn-outline",
106
+ variantClass[variant],
107
+ sizeClass[size],
108
+ shapeClass[shape],
109
+ split && "ph-btn-split",
110
+ className
111
+ )
112
+ }, props), {
113
+ children: content
114
+ })
115
+ );
116
+ });
117
+ Button.displayName = "Button";
118
+
119
+ // src/components/ui/Alert.tsx
120
+ import { forwardRef as forwardRef2 } from "react";
121
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
122
+ var statusConfig = {
123
+ info: { icon: IconInfo },
124
+ success: { icon: IconCheckCircle },
125
+ warning: { icon: IconExclamation },
126
+ danger: { icon: IconCancel }
127
+ };
128
+ var statusClassMap = {
129
+ info: "ph-alert-info",
130
+ success: "ph-alert-success",
131
+ warning: "ph-alert-warning",
132
+ danger: "ph-alert-danger"
133
+ };
134
+ var Alert = forwardRef2(function Alert2(_a, ref) {
135
+ var _b = _a, {
136
+ status = "info",
137
+ title,
138
+ description,
139
+ icon,
140
+ children,
141
+ className,
142
+ onDismiss,
143
+ live,
144
+ dismissLabel = "Dismiss notification",
145
+ role
146
+ } = _b, props = __objRest(_b, [
147
+ "status",
148
+ "title",
149
+ "description",
150
+ "icon",
151
+ "children",
152
+ "className",
153
+ "onDismiss",
154
+ "live",
155
+ "dismissLabel",
156
+ "role"
157
+ ]);
158
+ const config = statusConfig[status];
159
+ const Icon = config.icon;
160
+ return /* @__PURE__ */ jsxs2(
161
+ "div",
162
+ __spreadProps(__spreadValues({
163
+ ref,
164
+ role: role != null ? role : live === "assertive" ? "alert" : live === "polite" ? "status" : void 0,
165
+ "aria-live": live,
166
+ className: cn("ph-alert", statusClassMap[status], className)
167
+ }, props), {
168
+ children: [
169
+ icon != null ? icon : /* @__PURE__ */ jsx2(Icon, { className: "ph-alert-icon mt-0.5 h-5 w-5 shrink-0", "aria-hidden": true }),
170
+ /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
171
+ title && /* @__PURE__ */ jsx2("p", { className: "font-semibold", children: title }),
172
+ description && /* @__PURE__ */ jsx2("p", { className: "mt-1 text-sm text-ph-subtle", children: description }),
173
+ children
174
+ ] }),
175
+ onDismiss && /* @__PURE__ */ jsx2(
176
+ "button",
177
+ {
178
+ type: "button",
179
+ onClick: onDismiss,
180
+ className: "ph-alert-dismiss",
181
+ "aria-label": dismissLabel,
182
+ children: /* @__PURE__ */ jsx2(IconClose, { className: "h-4 w-4", "aria-hidden": true })
183
+ }
184
+ )
185
+ ]
186
+ })
187
+ );
188
+ });
189
+ Alert.displayName = "Alert";
190
+
191
+ // src/components/ui/Badge.tsx
192
+ import { forwardRef as forwardRef3 } from "react";
193
+ import { jsx as jsx3 } from "react/jsx-runtime";
194
+ var variantMap = {
195
+ brand: "ph-badge-brand",
196
+ neutral: "ph-badge-neutral",
197
+ success: "ph-badge-success",
198
+ warning: "ph-badge-warning",
199
+ danger: "ph-badge-danger",
200
+ info: "ph-badge-info",
201
+ outline: "ph-badge-outline"
202
+ };
203
+ var sizeMap = {
204
+ sm: "text-[10px] px-1.5 py-0.5",
205
+ md: ""
206
+ };
207
+ var Badge = forwardRef3(function Badge2(_a, ref) {
208
+ var _b = _a, {
209
+ variant = "neutral",
210
+ size = "md",
211
+ children,
212
+ className
213
+ } = _b, props = __objRest(_b, [
214
+ "variant",
215
+ "size",
216
+ "children",
217
+ "className"
218
+ ]);
219
+ return /* @__PURE__ */ jsx3(
220
+ "span",
221
+ __spreadProps(__spreadValues({
222
+ ref,
223
+ className: cn(
224
+ "ph-badge",
225
+ variantMap[variant],
226
+ sizeMap[size],
227
+ className
228
+ )
229
+ }, props), {
230
+ children
231
+ })
232
+ );
233
+ });
234
+ Badge.displayName = "Badge";
235
+
236
+ // src/components/ui/Card.tsx
237
+ import { forwardRef as forwardRef4 } from "react";
238
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
239
+ var variantMap2 = {
240
+ default: "",
241
+ outlined: "border-2 border-ph-border",
242
+ elevated: "ph-card-elevated",
243
+ highlighted: "ph-card-highlighted"
244
+ };
245
+ var Card = forwardRef4(function Card2(_a, ref) {
246
+ var _b = _a, {
247
+ children,
248
+ title,
249
+ description,
250
+ actions,
251
+ footer,
252
+ media,
253
+ variant = "default",
254
+ className,
255
+ bodyClassName,
256
+ interactive = false,
257
+ titleAs: Title2 = "h3"
258
+ } = _b, props = __objRest(_b, [
259
+ "children",
260
+ "title",
261
+ "description",
262
+ "actions",
263
+ "footer",
264
+ "media",
265
+ "variant",
266
+ "className",
267
+ "bodyClassName",
268
+ "interactive",
269
+ "titleAs"
270
+ ]);
271
+ return /* @__PURE__ */ jsxs3(
272
+ "div",
273
+ __spreadProps(__spreadValues({
274
+ ref,
275
+ className: cn(
276
+ "ph-card",
277
+ variantMap2[variant],
278
+ interactive && "ph-card-interactive",
279
+ className
280
+ )
281
+ }, props), {
282
+ children: [
283
+ media && /* @__PURE__ */ jsx4("div", { className: "ph-card-media", children: media }),
284
+ /* @__PURE__ */ jsxs3("div", { className: cn("ph-card-body", bodyClassName), children: [
285
+ title && /* @__PURE__ */ jsx4(Title2, { className: "ph-card-title", children: title }),
286
+ description && /* @__PURE__ */ jsx4("p", { className: "text-sm text-ph-subtle", children: description }),
287
+ children,
288
+ actions && /* @__PURE__ */ jsx4("div", { className: "ph-card-actions", children: actions })
289
+ ] }),
290
+ footer && /* @__PURE__ */ jsx4("div", { className: "border-t border-ph-border px-6 py-4 text-xs text-ph-subtle", children: footer })
291
+ ]
292
+ })
293
+ );
294
+ });
295
+ Card.displayName = "Card";
296
+
297
+ // src/components/ui/Kbd.tsx
298
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
299
+ var platformLabels = {
300
+ text: {
301
+ command: "Command",
302
+ cmd: "Command",
303
+ option: "Option",
304
+ alt: "Alt",
305
+ control: "Control",
306
+ ctrl: "Control",
307
+ shift: "Shift"
308
+ },
309
+ mac: {
310
+ command: "\u2318",
311
+ cmd: "\u2318",
312
+ option: "\u2325",
313
+ alt: "\u2325",
314
+ control: "\u2303",
315
+ ctrl: "\u2303",
316
+ shift: "\u21E7"
317
+ },
318
+ windows: {
319
+ command: "Win",
320
+ cmd: "Win",
321
+ option: "Alt",
322
+ alt: "Alt",
323
+ control: "Ctrl",
324
+ ctrl: "Ctrl",
325
+ shift: "Shift"
326
+ }
327
+ };
328
+ var spokenLabels = {
329
+ "\u2318": "Command",
330
+ "\u2325": "Option",
331
+ "\u2303": "Control",
332
+ "\u21E7": "Shift",
333
+ "\u21B5": "Enter",
334
+ "\u23CE": "Enter",
335
+ "\u232B": "Backspace",
336
+ "\u238B": "Escape"
337
+ };
338
+ function Kbd(_a) {
339
+ var _b = _a, {
340
+ variant = "shortcut",
341
+ keys,
342
+ platform = "text",
343
+ separator,
344
+ children,
345
+ className,
346
+ "aria-label": ariaLabel
347
+ } = _b, props = __objRest(_b, [
348
+ "variant",
349
+ "keys",
350
+ "platform",
351
+ "separator",
352
+ "children",
353
+ "className",
354
+ "aria-label"
355
+ ]);
356
+ if (variant === "token") {
357
+ return /* @__PURE__ */ jsx5("code", __spreadProps(__spreadValues({ className: cn("ph-code-token ph-kbd", className), "aria-label": ariaLabel }, props), { children }));
358
+ }
359
+ const sourceKeys = (keys == null ? void 0 : keys.length) ? keys : children != null ? [children] : [];
360
+ const displayKeys = sourceKeys.map((key) => formatKey(key, platform));
361
+ const accessibleLabel = ariaLabel != null ? ariaLabel : getShortcutLabel(displayKeys);
362
+ if (variant === "key") {
363
+ return /* @__PURE__ */ jsx5("kbd", __spreadProps(__spreadValues({ className: cn("ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys[0] }));
364
+ }
365
+ return /* @__PURE__ */ jsx5("kbd", __spreadProps(__spreadValues({ className: cn("ph-shortcut-group ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys.map((key, index) => /* @__PURE__ */ jsxs4("span", { className: "contents", children: [
366
+ index > 0 && separator != null ? /* @__PURE__ */ jsx5("span", { className: "ph-shortcut-separator", "aria-hidden": "true", children: separator }) : null,
367
+ /* @__PURE__ */ jsx5("span", { className: "ph-shortcut-key", "aria-hidden": accessibleLabel ? true : void 0, children: key })
368
+ ] }, index)) }));
369
+ }
370
+ function formatKey(key, platform) {
371
+ var _a;
372
+ if (typeof key !== "string") return key;
373
+ return (_a = platformLabels[platform][key.toLowerCase()]) != null ? _a : key;
374
+ }
375
+ function getShortcutLabel(keys) {
376
+ const labels = keys.map((key) => {
377
+ var _a;
378
+ if (typeof key !== "string" && typeof key !== "number") return null;
379
+ const value = String(key);
380
+ return (_a = spokenLabels[value]) != null ? _a : value;
381
+ });
382
+ return labels.every((label) => label != null) ? labels.join(" + ") : void 0;
383
+ }
384
+
385
+ // src/components/ui/Loader.tsx
386
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
387
+ var loaderSizeClass = {
388
+ sm: "ph-loader-sm",
389
+ md: "ph-loader-md",
390
+ lg: "ph-loader-lg"
391
+ };
392
+ var skeletonShapeClass = {
393
+ title: "ph-skeleton-title",
394
+ text: "ph-skeleton-text",
395
+ "short-text": "ph-skeleton-text-short",
396
+ avatar: "ph-skeleton-avatar",
397
+ button: "ph-skeleton-button",
398
+ block: "ph-skeleton-block"
399
+ };
400
+ function Loader(_a) {
401
+ var _b = _a, {
402
+ variant = "spinner",
403
+ size = "md",
404
+ label = "Loading",
405
+ className
406
+ } = _b, props = __objRest(_b, [
407
+ "variant",
408
+ "size",
409
+ "label",
410
+ "className"
411
+ ]);
412
+ return /* @__PURE__ */ jsxs5(
413
+ "span",
414
+ __spreadProps(__spreadValues({
415
+ role: "status",
416
+ "aria-label": label,
417
+ className: cn("ph-loader", loaderSizeClass[size], className)
418
+ }, props), {
419
+ children: [
420
+ variant === "spinner" ? /* @__PURE__ */ jsx6("span", { className: "ph-loading", "aria-hidden": true }) : null,
421
+ variant === "dots" ? /* @__PURE__ */ jsxs5("span", { className: "ph-loading-dots", "aria-hidden": true, children: [
422
+ /* @__PURE__ */ jsx6("span", {}),
423
+ /* @__PURE__ */ jsx6("span", {}),
424
+ /* @__PURE__ */ jsx6("span", {})
425
+ ] }) : null,
426
+ variant === "pulse" ? /* @__PURE__ */ jsx6("span", { className: "ph-loading-pulse", "aria-hidden": true }) : null
427
+ ]
428
+ })
429
+ );
430
+ }
431
+ function Skeleton(_a) {
432
+ var _b = _a, { shape = "text", className } = _b, props = __objRest(_b, ["shape", "className"]);
433
+ return /* @__PURE__ */ jsx6(
434
+ "span",
435
+ __spreadValues({
436
+ className: cn("ph-skeleton", skeletonShapeClass[shape], className),
437
+ "aria-hidden": "true"
438
+ }, props)
439
+ );
440
+ }
441
+ function LoadingState(_a) {
442
+ var _b = _a, {
443
+ label = "Loading",
444
+ title = "Loading",
445
+ description,
446
+ variant = "spinner",
447
+ size = "lg",
448
+ className
449
+ } = _b, props = __objRest(_b, [
450
+ "label",
451
+ "title",
452
+ "description",
453
+ "variant",
454
+ "size",
455
+ "className"
456
+ ]);
457
+ return /* @__PURE__ */ jsxs5("div", __spreadProps(__spreadValues({ className: cn("ph-loading-state", className), role: "status", "aria-label": label }, props), { children: [
458
+ /* @__PURE__ */ jsx6(Loader, { variant, size, label, "aria-hidden": "true" }),
459
+ /* @__PURE__ */ jsxs5("div", { className: "ph-loading-state__copy", children: [
460
+ /* @__PURE__ */ jsx6("strong", { children: title }),
461
+ description ? /* @__PURE__ */ jsx6("span", { children: description }) : null
462
+ ] })
463
+ ] }));
464
+ }
465
+
466
+ // src/components/ui/AuthLayout.tsx
467
+ import { useId } from "react";
468
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
469
+ function AuthLayout(_a) {
470
+ var _b = _a, { brand, footer, aside, children, className } = _b, props = __objRest(_b, ["brand", "footer", "aside", "children", "className"]);
471
+ return /* @__PURE__ */ jsxs6("div", __spreadProps(__spreadValues({ className: cn("ph-auth-layout", aside != null && "ph-auth-layout--split", className) }, props), { children: [
472
+ aside ? /* @__PURE__ */ jsx7("aside", { className: "ph-auth-layout__aside", children: aside }) : null,
473
+ /* @__PURE__ */ jsx7("div", { className: "ph-auth-layout__main", children: /* @__PURE__ */ jsxs6("div", { className: "ph-auth-layout__column", children: [
474
+ brand ? /* @__PURE__ */ jsx7("div", { className: "ph-auth-layout__brand", children: brand }) : null,
475
+ children,
476
+ footer ? /* @__PURE__ */ jsx7("footer", { className: "ph-auth-layout__footer", children: footer }) : null
477
+ ] }) })
478
+ ] }));
479
+ }
480
+ function AuthCard(_a) {
481
+ var _b = _a, { title, description, footer, children, className } = _b, props = __objRest(_b, ["title", "description", "footer", "children", "className"]);
482
+ const titleId = useId();
483
+ return /* @__PURE__ */ jsxs6("section", __spreadProps(__spreadValues({ className: cn("ph-auth-card", className), "aria-labelledby": titleId }, props), { children: [
484
+ /* @__PURE__ */ jsxs6("header", { className: "ph-auth-card__header", children: [
485
+ /* @__PURE__ */ jsx7("h1", { id: titleId, children: title }),
486
+ description ? /* @__PURE__ */ jsx7("p", { children: description }) : null
487
+ ] }),
488
+ /* @__PURE__ */ jsx7("div", { className: "ph-auth-card__body", children }),
489
+ footer ? /* @__PURE__ */ jsx7("footer", { className: "ph-auth-card__footer", children: footer }) : null
490
+ ] }));
491
+ }
492
+ function AuthDivider(_a) {
493
+ var _b = _a, { children = "or continue with", className } = _b, props = __objRest(_b, ["children", "className"]);
494
+ return /* @__PURE__ */ jsx7("div", __spreadProps(__spreadValues({ className: cn("ph-auth-divider", className) }, props), { children: /* @__PURE__ */ jsx7("span", { children }) }));
495
+ }
496
+
497
+ // src/components/ui/SettingsLayout.tsx
498
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
499
+ function SettingsNav(_a) {
500
+ var _b = _a, { groups, className } = _b, props = __objRest(_b, ["groups", "className"]);
501
+ return /* @__PURE__ */ jsx8("div", __spreadProps(__spreadValues({ className: cn("ph-settings-nav", className) }, props), { children: groups.map((group, index) => /* @__PURE__ */ jsxs7("div", { className: "ph-settings-nav__group", children: [
502
+ /* @__PURE__ */ jsx8("h3", { children: group.label }),
503
+ /* @__PURE__ */ jsx8("div", { className: "ph-settings-nav__items", children: group.items.map((item) => /* @__PURE__ */ jsxs7(
504
+ "a",
505
+ {
506
+ href: item.href,
507
+ id: `settings-nav-${item.id}`,
508
+ "data-test": `settings-nav-${item.id}`,
509
+ className: cn(
510
+ "ph-settings-nav__item",
511
+ item.active && "ph-settings-nav__item--active"
512
+ ),
513
+ "aria-current": item.active ? "page" : void 0,
514
+ children: [
515
+ item.icon ? /* @__PURE__ */ jsx8("span", { className: "ph-settings-nav__icon", children: item.icon }) : null,
516
+ /* @__PURE__ */ jsx8("span", { children: item.label }),
517
+ item.badge ? /* @__PURE__ */ jsx8("span", { className: "ph-settings-nav__badge", children: item.badge }) : null
518
+ ]
519
+ },
520
+ item.id
521
+ )) })
522
+ ] }, index)) }));
523
+ }
524
+ function SettingsLayout(_a) {
525
+ var _b = _a, {
526
+ title,
527
+ description,
528
+ actions,
529
+ navigation,
530
+ navigationLabel = "Settings",
531
+ children,
532
+ className
533
+ } = _b, props = __objRest(_b, [
534
+ "title",
535
+ "description",
536
+ "actions",
537
+ "navigation",
538
+ "navigationLabel",
539
+ "children",
540
+ "className"
541
+ ]);
542
+ return /* @__PURE__ */ jsxs7("section", __spreadProps(__spreadValues({ className: cn("ph-settings-layout", className) }, props), { children: [
543
+ /* @__PURE__ */ jsxs7("header", { className: "ph-settings-layout__header", children: [
544
+ /* @__PURE__ */ jsxs7("div", { children: [
545
+ /* @__PURE__ */ jsx8("h2", { children: title }),
546
+ description ? /* @__PURE__ */ jsx8("p", { children: description }) : null
547
+ ] }),
548
+ actions ? /* @__PURE__ */ jsx8("div", { className: "ph-settings-layout__actions", children: actions }) : null
549
+ ] }),
550
+ /* @__PURE__ */ jsxs7("details", { className: "ph-settings-layout__mobile-nav", children: [
551
+ /* @__PURE__ */ jsxs7("summary", { children: [
552
+ /* @__PURE__ */ jsx8(IconTuning, { className: "h-4 w-4", "aria-hidden": true }),
553
+ "Settings menu"
554
+ ] }),
555
+ /* @__PURE__ */ jsx8("nav", { "aria-label": navigationLabel, children: navigation })
556
+ ] }),
557
+ /* @__PURE__ */ jsxs7("div", { className: "ph-settings-layout__grid", children: [
558
+ /* @__PURE__ */ jsx8("aside", { className: "ph-settings-layout__sidebar", children: /* @__PURE__ */ jsx8("nav", { "aria-label": navigationLabel, children: navigation }) }),
559
+ /* @__PURE__ */ jsx8("div", { className: "ph-settings-layout__content", children })
560
+ ] })
561
+ ] }));
562
+ }
563
+
564
+ // src/components/ui/Input.tsx
565
+ import { forwardRef as forwardRef5, useId as useId3 } from "react";
566
+
567
+ // src/components/ui/FormField.tsx
568
+ import { useId as useId2 } from "react";
569
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
570
+ function FormField(_a) {
571
+ var _b = _a, {
572
+ controlId,
573
+ label,
574
+ hideLabel = false,
575
+ helperText,
576
+ error,
577
+ required = false,
578
+ disabled = false,
579
+ children,
580
+ className
581
+ } = _b, props = __objRest(_b, [
582
+ "controlId",
583
+ "label",
584
+ "hideLabel",
585
+ "helperText",
586
+ "error",
587
+ "required",
588
+ "disabled",
589
+ "children",
590
+ "className"
591
+ ]);
592
+ const generatedId = useId2();
593
+ const id = controlId != null ? controlId : generatedId;
594
+ const descriptionId = helperText && !error ? `${id}-description` : void 0;
595
+ const errorId = error ? `${id}-error` : void 0;
596
+ const controlProps = {
597
+ id,
598
+ "aria-describedby": descriptionId,
599
+ "aria-errormessage": errorId,
600
+ "aria-invalid": error ? true : void 0
601
+ };
602
+ return /* @__PURE__ */ jsxs8("div", __spreadProps(__spreadValues({ className: cn("ph-field", className) }, props), { children: [
603
+ label ? /* @__PURE__ */ jsxs8(
604
+ "label",
605
+ {
606
+ htmlFor: id,
607
+ className: cn("ph-label", hideLabel && "sr-only", disabled && "opacity-50"),
608
+ children: [
609
+ label,
610
+ required ? /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: " *" }) : null
611
+ ]
612
+ }
613
+ ) : null,
614
+ typeof children === "function" ? children(controlProps) : children,
615
+ descriptionId ? /* @__PURE__ */ jsx9("p", { id: descriptionId, className: "mt-1 text-xs text-ph-subtle", children: helperText }) : null,
616
+ errorId ? /* @__PURE__ */ jsx9("p", { id: errorId, className: "mt-1 text-xs font-medium text-ph-danger", children: error }) : null
617
+ ] }));
618
+ }
619
+
620
+ // src/components/ui/Input.tsx
621
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
622
+ var sizeMap2 = {
623
+ sm: "ph-input-sm",
624
+ md: "",
625
+ lg: "ph-input-lg"
626
+ };
627
+ function joinIds(...ids) {
628
+ const value = ids.filter(Boolean).join(" ");
629
+ return value || void 0;
630
+ }
631
+ var Input = forwardRef5(function Input2(_a, ref) {
632
+ var _b = _a, {
633
+ id: idProp,
634
+ label,
635
+ hideLabel = false,
636
+ error,
637
+ helperText,
638
+ size = "md",
639
+ variant = "default",
640
+ className,
641
+ wrapperClassName,
642
+ disabled,
643
+ required,
644
+ "aria-describedby": ariaDescribedBy
645
+ } = _b, props = __objRest(_b, [
646
+ "id",
647
+ "label",
648
+ "hideLabel",
649
+ "error",
650
+ "helperText",
651
+ "size",
652
+ "variant",
653
+ "className",
654
+ "wrapperClassName",
655
+ "disabled",
656
+ "required",
657
+ "aria-describedby"
658
+ ]);
659
+ const autoId = useId3();
660
+ const id = idProp != null ? idProp : autoId;
661
+ const hasError = Boolean(error);
662
+ return /* @__PURE__ */ jsx10(
663
+ FormField,
664
+ {
665
+ controlId: id,
666
+ label,
667
+ hideLabel,
668
+ helperText,
669
+ error,
670
+ required,
671
+ disabled,
672
+ className: wrapperClassName,
673
+ children: (fieldProps) => /* @__PURE__ */ jsx10(
674
+ "input",
675
+ __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
676
+ ref,
677
+ disabled,
678
+ required,
679
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
680
+ className: cn(
681
+ "ph-input w-full",
682
+ sizeMap2[size],
683
+ variant === "ghost" && "ph-input-ghost",
684
+ hasError && "ph-input-error",
685
+ disabled && "cursor-not-allowed opacity-60",
686
+ className
687
+ )
688
+ }), props)
689
+ )
690
+ }
691
+ );
692
+ });
693
+ Input.displayName = "Input";
694
+ var Select = forwardRef5(function Select2(_a, ref) {
695
+ var _b = _a, {
696
+ id: idProp,
697
+ label,
698
+ hideLabel = false,
699
+ error,
700
+ helperText,
701
+ size = "md",
702
+ className,
703
+ wrapperClassName,
704
+ disabled,
705
+ children,
706
+ required,
707
+ "aria-describedby": ariaDescribedBy
708
+ } = _b, props = __objRest(_b, [
709
+ "id",
710
+ "label",
711
+ "hideLabel",
712
+ "error",
713
+ "helperText",
714
+ "size",
715
+ "className",
716
+ "wrapperClassName",
717
+ "disabled",
718
+ "children",
719
+ "required",
720
+ "aria-describedby"
721
+ ]);
722
+ const autoId = useId3();
723
+ const id = idProp != null ? idProp : autoId;
724
+ const hasError = Boolean(error);
725
+ return /* @__PURE__ */ jsx10(FormField, { controlId: id, label, hideLabel, helperText, error, required, disabled, className: wrapperClassName, children: (fieldProps) => /* @__PURE__ */ jsx10(
726
+ "select",
727
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
728
+ ref,
729
+ disabled,
730
+ required,
731
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
732
+ className: cn(
733
+ "ph-select w-full",
734
+ sizeMap2[size],
735
+ hasError && "ph-input-error",
736
+ disabled && "cursor-not-allowed opacity-60",
737
+ className
738
+ )
739
+ }), props), {
740
+ children
741
+ })
742
+ ) });
743
+ });
744
+ Select.displayName = "Select";
745
+ var Textarea = forwardRef5(function Textarea2(_a, ref) {
746
+ var _b = _a, {
747
+ id: idProp,
748
+ label,
749
+ hideLabel = false,
750
+ error,
751
+ helperText,
752
+ size = "md",
753
+ className,
754
+ wrapperClassName,
755
+ disabled,
756
+ required,
757
+ "aria-describedby": ariaDescribedBy
758
+ } = _b, props = __objRest(_b, [
759
+ "id",
760
+ "label",
761
+ "hideLabel",
762
+ "error",
763
+ "helperText",
764
+ "size",
765
+ "className",
766
+ "wrapperClassName",
767
+ "disabled",
768
+ "required",
769
+ "aria-describedby"
770
+ ]);
771
+ const autoId = useId3();
772
+ const id = idProp != null ? idProp : autoId;
773
+ const hasError = Boolean(error);
774
+ return /* @__PURE__ */ jsx10(FormField, { controlId: id, label, hideLabel, helperText, error, required, disabled, className: wrapperClassName, children: (fieldProps) => /* @__PURE__ */ jsx10(
775
+ "textarea",
776
+ __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
777
+ ref,
778
+ disabled,
779
+ required,
780
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
781
+ className: cn(
782
+ "ph-textarea w-full",
783
+ sizeMap2[size],
784
+ hasError && "ph-input-error",
785
+ disabled && "cursor-not-allowed opacity-60",
786
+ className
787
+ )
788
+ }), props)
789
+ ) });
790
+ });
791
+ Textarea.displayName = "Textarea";
792
+ var Checkbox = forwardRef5(function Checkbox2(_a, ref) {
793
+ var _b = _a, {
794
+ id: idProp,
795
+ label,
796
+ error,
797
+ helperText,
798
+ className,
799
+ wrapperClassName,
800
+ disabled,
801
+ "aria-describedby": ariaDescribedBy
802
+ } = _b, props = __objRest(_b, [
803
+ "id",
804
+ "label",
805
+ "error",
806
+ "helperText",
807
+ "className",
808
+ "wrapperClassName",
809
+ "disabled",
810
+ "aria-describedby"
811
+ ]);
812
+ const autoId = useId3();
813
+ const id = idProp != null ? idProp : autoId;
814
+ const hasError = Boolean(error);
815
+ const descriptionId = helperText && !hasError ? `${id}-description` : void 0;
816
+ const errorId = error ? `${id}-error` : void 0;
817
+ return /* @__PURE__ */ jsxs9("div", { className: cn("ph-control-row", wrapperClassName), children: [
818
+ /* @__PURE__ */ jsxs9("span", { className: "ph-checkbox-wrap", children: [
819
+ /* @__PURE__ */ jsx10(
820
+ "input",
821
+ __spreadValues({
822
+ ref,
823
+ id,
824
+ type: "checkbox",
825
+ disabled,
826
+ "aria-invalid": hasError || void 0,
827
+ "aria-describedby": joinIds(ariaDescribedBy, descriptionId),
828
+ "aria-errormessage": errorId,
829
+ className: cn(
830
+ "ph-checkbox",
831
+ hasError && "border-ph-danger",
832
+ disabled && "cursor-not-allowed opacity-60",
833
+ className
834
+ )
835
+ }, props)
836
+ ),
837
+ /* @__PURE__ */ jsx10(IconCheck, { className: "ph-checkbox-icon", "aria-hidden": true })
838
+ ] }),
839
+ /* @__PURE__ */ jsxs9("div", { className: "ph-control-copy", children: [
840
+ /* @__PURE__ */ jsx10("label", { htmlFor: id, className: cn("cursor-pointer", disabled && "opacity-60"), children: label }),
841
+ descriptionId ? /* @__PURE__ */ jsx10("p", { id: descriptionId, className: "text-xs text-ph-subtle", children: helperText }) : null,
842
+ errorId ? /* @__PURE__ */ jsx10("p", { id: errorId, className: "text-xs font-medium text-ph-danger", children: error }) : null
843
+ ] })
844
+ ] });
845
+ });
846
+ Checkbox.displayName = "Checkbox";
847
+ var Radio = forwardRef5(function Radio2(_a, ref) {
848
+ var _b = _a, {
849
+ id: idProp,
850
+ label,
851
+ className,
852
+ wrapperClassName,
853
+ disabled
854
+ } = _b, props = __objRest(_b, [
855
+ "id",
856
+ "label",
857
+ "className",
858
+ "wrapperClassName",
859
+ "disabled"
860
+ ]);
861
+ const autoId = useId3();
862
+ const id = idProp != null ? idProp : autoId;
863
+ return /* @__PURE__ */ jsxs9("div", { className: cn("ph-control-row", wrapperClassName, disabled && "opacity-60"), children: [
864
+ /* @__PURE__ */ jsx10(
865
+ "input",
866
+ __spreadValues({
867
+ ref,
868
+ id,
869
+ type: "radio",
870
+ disabled,
871
+ className: cn("ph-radio", disabled && "cursor-not-allowed", className)
872
+ }, props)
873
+ ),
874
+ /* @__PURE__ */ jsx10("label", { htmlFor: id, className: cn("cursor-pointer", disabled && "opacity-60"), children: label })
875
+ ] });
876
+ });
877
+ Radio.displayName = "Radio";
878
+ var Toggle = forwardRef5(function Toggle2(_a, ref) {
879
+ var _b = _a, {
880
+ id: idProp,
881
+ label,
882
+ className,
883
+ wrapperClassName,
884
+ disabled
885
+ } = _b, props = __objRest(_b, [
886
+ "id",
887
+ "label",
888
+ "className",
889
+ "wrapperClassName",
890
+ "disabled"
891
+ ]);
892
+ const autoId = useId3();
893
+ const id = idProp != null ? idProp : autoId;
894
+ return /* @__PURE__ */ jsxs9("label", { className: cn("ph-control-row-between", wrapperClassName, disabled && "opacity-60"), children: [
895
+ /* @__PURE__ */ jsx10("span", { className: disabled ? "opacity-60" : void 0, children: label }),
896
+ /* @__PURE__ */ jsx10(
897
+ "input",
898
+ __spreadValues({
899
+ ref,
900
+ id,
901
+ type: "checkbox",
902
+ role: "switch",
903
+ disabled,
904
+ className: cn("ph-toggle", disabled && "cursor-not-allowed", className)
905
+ }, props)
906
+ )
907
+ ] });
908
+ });
909
+ Toggle.displayName = "Toggle";
910
+ var Range = forwardRef5(function Range2(_a, ref) {
911
+ var _b = _a, {
912
+ id: idProp,
913
+ label,
914
+ minLabel,
915
+ maxLabel,
916
+ valueLabel,
917
+ wrapperClassName,
918
+ className
919
+ } = _b, props = __objRest(_b, [
920
+ "id",
921
+ "label",
922
+ "minLabel",
923
+ "maxLabel",
924
+ "valueLabel",
925
+ "wrapperClassName",
926
+ "className"
927
+ ]);
928
+ const autoId = useId3();
929
+ const id = idProp != null ? idProp : autoId;
930
+ return /* @__PURE__ */ jsxs9("div", { className: cn("ph-field", wrapperClassName), children: [
931
+ label && /* @__PURE__ */ jsx10("label", { htmlFor: id, className: "ph-label", children: label }),
932
+ /* @__PURE__ */ jsx10("input", __spreadValues({ ref, id, type: "range", className: cn("ph-range", className) }, props)),
933
+ (minLabel || valueLabel || maxLabel) && /* @__PURE__ */ jsxs9("div", { className: "flex justify-between text-xs text-ph-mutedtext", children: [
934
+ /* @__PURE__ */ jsx10("span", { children: minLabel }),
935
+ /* @__PURE__ */ jsx10("span", { children: valueLabel }),
936
+ /* @__PURE__ */ jsx10("span", { children: maxLabel })
937
+ ] })
938
+ ] });
939
+ });
940
+ Range.displayName = "Range";
941
+ var FileUpload = forwardRef5(function FileUpload2(_a, ref) {
942
+ var _b = _a, {
943
+ id: idProp,
944
+ label,
945
+ prompt = "Drop file or browse",
946
+ wrapperClassName,
947
+ className
948
+ } = _b, props = __objRest(_b, [
949
+ "id",
950
+ "label",
951
+ "prompt",
952
+ "wrapperClassName",
953
+ "className"
954
+ ]);
955
+ const autoId = useId3();
956
+ const id = idProp != null ? idProp : autoId;
957
+ return /* @__PURE__ */ jsxs9("div", { className: cn("ph-field", wrapperClassName), children: [
958
+ label && /* @__PURE__ */ jsx10("label", { htmlFor: id, className: "ph-label", children: label }),
959
+ /* @__PURE__ */ jsxs9("label", { htmlFor: id, className: "ph-file-upload", children: [
960
+ /* @__PURE__ */ jsx10("input", __spreadValues({ ref, id, type: "file", className: cn("sr-only", className) }, props)),
961
+ prompt
962
+ ] })
963
+ ] });
964
+ });
965
+ FileUpload.displayName = "FileUpload";
966
+
967
+ // src/components/ui/Modal.tsx
968
+ import * as Dialog from "@radix-ui/react-dialog";
969
+ import { useRef } from "react";
970
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
971
+ var sizeMap3 = {
972
+ sm: "max-w-sm",
973
+ md: "max-w-lg",
974
+ lg: "max-w-2xl",
975
+ xl: "max-w-4xl",
976
+ full: "max-w-none"
977
+ };
978
+ function Modal({
979
+ open = false,
980
+ onClose,
981
+ title,
982
+ description,
983
+ children,
984
+ footer,
985
+ size = "md",
986
+ className,
987
+ customLayout = false,
988
+ showCloseButton = true,
989
+ closeOnOutsideClick = true,
990
+ closeOnEscape = true,
991
+ dataTest,
992
+ panelDataTest,
993
+ zIndex,
994
+ id,
995
+ "aria-label": ariaLabel,
996
+ "aria-labelledby": ariaLabelledBy
997
+ }) {
998
+ const canDismiss = Boolean(onClose);
999
+ const restoreFocusRef = useRef(null);
1000
+ return /* @__PURE__ */ jsx11(
1001
+ Dialog.Root,
1002
+ {
1003
+ open,
1004
+ onOpenChange: (nextOpen) => {
1005
+ if (!nextOpen) onClose == null ? void 0 : onClose();
1006
+ },
1007
+ children: /* @__PURE__ */ jsxs10(Dialog.Portal, { children: [
1008
+ /* @__PURE__ */ jsx11(
1009
+ Dialog.Overlay,
1010
+ {
1011
+ "data-test": dataTest,
1012
+ className: "ph-modal-overlay",
1013
+ style: zIndex ? { zIndex } : void 0
1014
+ }
1015
+ ),
1016
+ /* @__PURE__ */ jsx11(
1017
+ Dialog.Content,
1018
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues(__spreadValues({
1019
+ id,
1020
+ "data-test": panelDataTest,
1021
+ className: cn("ph-modal-panel", sizeMap3[size], className)
1022
+ }, ariaLabel ? { "aria-label": ariaLabel } : {}), ariaLabelledBy ? { "aria-labelledby": ariaLabelledBy } : {}), {
1023
+ style: zIndex ? { zIndex } : void 0
1024
+ }), description ? {} : { "aria-describedby": void 0 }), {
1025
+ onOpenAutoFocus: () => {
1026
+ restoreFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1027
+ },
1028
+ onCloseAutoFocus: (event) => {
1029
+ var _a;
1030
+ event.preventDefault();
1031
+ (_a = restoreFocusRef.current) == null ? void 0 : _a.focus();
1032
+ },
1033
+ onEscapeKeyDown: (event) => {
1034
+ if (!canDismiss || !closeOnEscape) event.preventDefault();
1035
+ },
1036
+ onPointerDownOutside: (event) => {
1037
+ if (!canDismiss || !closeOnOutsideClick) event.preventDefault();
1038
+ },
1039
+ children: customLayout ? /* @__PURE__ */ jsxs10(Fragment2, { children: [
1040
+ /* @__PURE__ */ jsx11(Dialog.Title, { className: "sr-only", children: ariaLabel != null ? ariaLabel : "Dialog" }),
1041
+ children
1042
+ ] }) : /* @__PURE__ */ jsxs10(Fragment2, { children: [
1043
+ title ? null : /* @__PURE__ */ jsx11(Dialog.Title, { className: "sr-only", children: ariaLabel != null ? ariaLabel : "Dialog" }),
1044
+ title || description || showCloseButton && canDismiss ? /* @__PURE__ */ jsxs10("header", { className: "ph-modal-header", children: [
1045
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
1046
+ title ? /* @__PURE__ */ jsx11(Dialog.Title, { className: "text-lg font-bold text-ph-ink", children: title }) : null,
1047
+ description ? /* @__PURE__ */ jsx11(Dialog.Description, { className: "mt-1 text-sm text-ph-subtle", children: description }) : null
1048
+ ] }),
1049
+ showCloseButton && canDismiss ? /* @__PURE__ */ jsx11(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx11(
1050
+ "button",
1051
+ {
1052
+ type: "button",
1053
+ className: "ph-modal-close",
1054
+ "aria-label": "Close dialog",
1055
+ children: /* @__PURE__ */ jsx11(IconClose, { className: "h-5 w-5", "aria-hidden": true })
1056
+ }
1057
+ ) }) : null
1058
+ ] }) : null,
1059
+ /* @__PURE__ */ jsx11("div", { className: "ph-modal-body", children }),
1060
+ footer ? /* @__PURE__ */ jsx11("div", { className: "ph-modal-footer", children: footer }) : null
1061
+ ] })
1062
+ })
1063
+ )
1064
+ ] })
1065
+ }
1066
+ );
1067
+ }
1068
+
1069
+ // src/components/ui/Panel.tsx
1070
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1071
+ function Panel(_a) {
1072
+ var _b = _a, { title, description, children, className } = _b, props = __objRest(_b, ["title", "description", "children", "className"]);
1073
+ return /* @__PURE__ */ jsxs11("div", __spreadProps(__spreadValues({ className: cn("ph-panel", className) }, props), { children: [
1074
+ title && /* @__PURE__ */ jsx12("h3", { className: "text-sm font-semibold uppercase tracking-wider text-ph-mutedtext", children: title }),
1075
+ description && /* @__PURE__ */ jsx12("p", { className: "text-sm text-ph-subtle", children: description }),
1076
+ children
1077
+ ] }));
1078
+ }
1079
+
1080
+ // src/components/ui/SearchInput.tsx
1081
+ import { useId as useId4 } from "react";
1082
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1083
+ function SearchInput(_a) {
1084
+ var _b = _a, {
1085
+ id: idProp,
1086
+ label = "Search",
1087
+ hideLabel = false,
1088
+ shortcut,
1089
+ density = "default",
1090
+ className,
1091
+ wrapperClassName,
1092
+ placeholder
1093
+ } = _b, props = __objRest(_b, [
1094
+ "id",
1095
+ "label",
1096
+ "hideLabel",
1097
+ "shortcut",
1098
+ "density",
1099
+ "className",
1100
+ "wrapperClassName",
1101
+ "placeholder"
1102
+ ]);
1103
+ const autoId = useId4();
1104
+ const id = idProp != null ? idProp : autoId;
1105
+ return /* @__PURE__ */ jsxs12("div", { className: cn("relative", wrapperClassName), children: [
1106
+ /* @__PURE__ */ jsx13("label", { htmlFor: id, className: hideLabel ? "sr-only" : "ph-label mb-1.5 block", children: label }),
1107
+ /* @__PURE__ */ jsxs12("div", { className: "relative", children: [
1108
+ shortcut != null ? /* @__PURE__ */ jsx13(
1109
+ "span",
1110
+ {
1111
+ className: "ph-shortcut pointer-events-none absolute left-3 top-1/2 z-10 -translate-y-1/2 text-xs",
1112
+ "aria-hidden": true,
1113
+ children: shortcut
1114
+ }
1115
+ ) : null,
1116
+ /* @__PURE__ */ jsx13(
1117
+ "input",
1118
+ __spreadValues({
1119
+ id,
1120
+ type: "search",
1121
+ placeholder,
1122
+ "aria-label": hideLabel ? label : void 0,
1123
+ className: cn(
1124
+ "ph-input w-full",
1125
+ density === "compact" && "max-w-xs !min-h-[2rem] py-1.5 text-sm",
1126
+ shortcut != null && "pl-[3.25rem]",
1127
+ className
1128
+ )
1129
+ }, props)
1130
+ )
1131
+ ] })
1132
+ ] });
1133
+ }
1134
+ function SearchGroup(_a) {
1135
+ var _b = _a, {
1136
+ id: idProp,
1137
+ label = "Search records",
1138
+ submitLabel = "Search",
1139
+ placeholder = "Persons, actions, flags\u2026",
1140
+ wrapperClassName,
1141
+ className
1142
+ } = _b, props = __objRest(_b, [
1143
+ "id",
1144
+ "label",
1145
+ "submitLabel",
1146
+ "placeholder",
1147
+ "wrapperClassName",
1148
+ "className"
1149
+ ]);
1150
+ const autoId = useId4();
1151
+ const id = idProp != null ? idProp : autoId;
1152
+ return /* @__PURE__ */ jsxs12("div", { className: cn("ph-field", wrapperClassName), children: [
1153
+ /* @__PURE__ */ jsx13("label", { htmlFor: id, className: "ph-label", children: label }),
1154
+ /* @__PURE__ */ jsxs12("div", { className: "ph-search-group flex w-full max-w-lg min-h-[2.3125rem] items-stretch divide-x divide-ph-border", children: [
1155
+ /* @__PURE__ */ jsx13(
1156
+ "input",
1157
+ __spreadValues({
1158
+ id,
1159
+ type: "search",
1160
+ placeholder,
1161
+ className: cn("ph-input ph-input-group-field min-w-0 flex-1", className)
1162
+ }, props)
1163
+ ),
1164
+ /* @__PURE__ */ jsx13(
1165
+ Button,
1166
+ {
1167
+ type: "submit",
1168
+ variant: "primary",
1169
+ icon: /* @__PURE__ */ jsx13(IconSearch, { className: "h-4 w-4", "aria-hidden": true }),
1170
+ className: "ph-search-group__submit",
1171
+ "aria-label": submitLabel
1172
+ }
1173
+ )
1174
+ ] })
1175
+ ] });
1176
+ }
1177
+
1178
+ // src/components/ui/Table.tsx
1179
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1180
+ function Table({
1181
+ data,
1182
+ columns,
1183
+ zebra = false,
1184
+ compact = false,
1185
+ ribbon = false,
1186
+ getRowStyle,
1187
+ className,
1188
+ caption
1189
+ }) {
1190
+ return /* @__PURE__ */ jsx14("div", { className: cn("ph-table-wrap", compact && "ph-table-compact", className), children: /* @__PURE__ */ jsxs13("table", { className: cn("ph-table", zebra && "ph-table-zebra", ribbon && "ph-table--ribbon"), children: [
1191
+ caption && /* @__PURE__ */ jsx14("caption", { className: "sr-only", children: caption }),
1192
+ /* @__PURE__ */ jsx14("thead", { children: /* @__PURE__ */ jsx14("tr", { children: columns.map((col) => /* @__PURE__ */ jsx14("th", { className: col.className, children: col.header }, col.key)) }) }),
1193
+ /* @__PURE__ */ jsx14("tbody", { children: data.map((row, i) => /* @__PURE__ */ jsx14("tr", { style: getRowStyle == null ? void 0 : getRowStyle(row), children: columns.map((col) => /* @__PURE__ */ jsx14("td", { className: col.className, children: col.cell(row) }, col.key)) }, i)) })
1194
+ ] }) });
1195
+ }
1196
+
1197
+ // src/components/ui/Stat.tsx
1198
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1199
+ var toneMap = {
1200
+ default: "text-ph-ink",
1201
+ brand: "text-ph-brand",
1202
+ blue: "text-ph-blue",
1203
+ purple: "text-ph-purple",
1204
+ warning: "text-amber-900"
1205
+ };
1206
+ var statMap = {
1207
+ default: "",
1208
+ brand: "",
1209
+ blue: "",
1210
+ purple: "",
1211
+ warning: "border-amber-200 bg-amber-50/70"
1212
+ };
1213
+ function Stat(_a) {
1214
+ var _b = _a, { icon, label, value, footer, tone = "default", className } = _b, props = __objRest(_b, ["icon", "label", "value", "footer", "tone", "className"]);
1215
+ return /* @__PURE__ */ jsxs14("article", __spreadProps(__spreadValues({ className: cn("ph-stat", statMap[tone], className) }, props), { children: [
1216
+ icon && /* @__PURE__ */ jsx15("div", { className: cn("mb-2 h-7 w-7", toneMap[tone]), children: icon }),
1217
+ /* @__PURE__ */ jsx15("div", { className: cn("ph-stat-label", tone === "warning" && toneMap[tone]), children: label }),
1218
+ /* @__PURE__ */ jsx15("div", { className: cn("ph-stat-val", toneMap[tone]), children: value }),
1219
+ footer && /* @__PURE__ */ jsx15("p", { className: "text-xs text-ph-subtle", children: footer })
1220
+ ] }));
1221
+ }
1222
+
1223
+ // src/components/ui/ThemeDomSync.tsx
1224
+ import { useLayoutEffect } from "react";
1225
+
1226
+ // src/themes/registry.ts
1227
+ var DEFAULT_THEME_ID = "hedgehog-light";
1228
+ var THEMES = [
1229
+ {
1230
+ id: "hedgehog-light",
1231
+ name: "HedgeHog Light",
1232
+ description: "Default Quill warm greys and orange Lemon chrome.",
1233
+ colorScheme: "light",
1234
+ group: "HedgeHog"
1235
+ },
1236
+ {
1237
+ id: "hedgehog-dark",
1238
+ name: "HedgeHog Dark",
1239
+ description: "Dark app shell with HedgeHog orange accents.",
1240
+ colorScheme: "dark",
1241
+ group: "HedgeHog"
1242
+ },
1243
+ {
1244
+ id: "note",
1245
+ name: "Note Light",
1246
+ description: "Notebook purple on lavender-white chrome.",
1247
+ colorScheme: "light",
1248
+ group: "Note"
1249
+ },
1250
+ {
1251
+ id: "note-dark",
1252
+ name: "Note Dark",
1253
+ description: "Dark notebook purple \u2014 night reading mode.",
1254
+ colorScheme: "dark",
1255
+ group: "Note"
1256
+ },
1257
+ {
1258
+ id: "turtletime",
1259
+ name: "TurtleTime Light",
1260
+ description: "Turtle mascot palette \u2014 shell orange, leaf green, and warm cream.",
1261
+ colorScheme: "light",
1262
+ group: "TurtleTime"
1263
+ },
1264
+ {
1265
+ id: "turtletime-dark",
1266
+ name: "TurtleTime Dark",
1267
+ description: "TurtleTime after dusk \u2014 dark olive shell with bright orange clock accents.",
1268
+ colorScheme: "dark",
1269
+ group: "TurtleTime"
1270
+ },
1271
+ {
1272
+ id: "rosepine-light",
1273
+ name: "Ros\xE9 Pine Light",
1274
+ description: "Ros\xE9 Pine Dawn \u2014 warm paper base with muted iris accents.",
1275
+ colorScheme: "light",
1276
+ group: "Ros\xE9 Pine"
1277
+ },
1278
+ {
1279
+ id: "rosepine-dark",
1280
+ name: "Ros\xE9 Pine Dark",
1281
+ description: "Ros\xE9 Pine Main \u2014 moonlit base with iris and love accents.",
1282
+ colorScheme: "dark",
1283
+ group: "Ros\xE9 Pine"
1284
+ },
1285
+ {
1286
+ id: "kraken-light",
1287
+ name: "Kraken Light",
1288
+ description: "Medium-inspired warm paper, editorial black actions, and publication yellow.",
1289
+ colorScheme: "light",
1290
+ group: "Kraken"
1291
+ },
1292
+ {
1293
+ id: "kraken-dark",
1294
+ name: "Kraken Dark",
1295
+ description: "Medium-inspired night reading canvas with white actions and publication yellow.",
1296
+ colorScheme: "dark",
1297
+ group: "Kraken"
1298
+ },
1299
+ {
1300
+ id: "deepsea-light",
1301
+ name: "Tokyo Day",
1302
+ description: "Tokyo Night Day \u2014 soft bluish greys with vivid blue and purple accents.",
1303
+ colorScheme: "light",
1304
+ group: "Tokyo Night"
1305
+ },
1306
+ {
1307
+ id: "deepsea-dark",
1308
+ name: "Tokyo Night",
1309
+ description: "Tokyo Night \u2014 #1a1b26 base with signature blue, cyan, and purple.",
1310
+ colorScheme: "dark",
1311
+ group: "Tokyo Night"
1312
+ },
1313
+ {
1314
+ id: "malibu-light",
1315
+ name: "Malibu Light",
1316
+ description: "Sun-bleached GTA San Andreas palette with hot pink, sunset orange, and lime signals.",
1317
+ colorScheme: "light",
1318
+ group: "Malibu"
1319
+ },
1320
+ {
1321
+ id: "malibu-dark",
1322
+ name: "Malibu Dark",
1323
+ description: "Deep plum command deck with hot pink, lime, cyan, and sunset signals.",
1324
+ colorScheme: "dark",
1325
+ group: "Malibu"
1326
+ }
1327
+ ];
1328
+ var THEME_GROUPS = Array.from(
1329
+ new Set(THEMES.map((theme) => theme.group))
1330
+ );
1331
+ function isThemeId(value) {
1332
+ return THEMES.some((theme) => theme.id === value);
1333
+ }
1334
+ function getTheme(id) {
1335
+ return THEMES.find((theme) => theme.id === id);
1336
+ }
1337
+
1338
+ // src/themes/init-theme.ts
1339
+ var STORAGE_KEY = "ph-theme";
1340
+ var VALID_THEMES = THEMES.map((theme) => theme.id);
1341
+ var THEME_INIT_SCRIPT = `(function(){try{var k="${STORAGE_KEY}",d="${DEFAULT_THEME_ID}",v=${JSON.stringify(VALID_THEMES)},t=localStorage.getItem(k);if(!t||v.indexOf(t)<0)t=d;document.documentElement.setAttribute("data-theme",t)}catch(e){document.documentElement.setAttribute("data-theme","${DEFAULT_THEME_ID}")}})();`;
1342
+ function persistTheme(themeId) {
1343
+ if (typeof window === "undefined") {
1344
+ return;
1345
+ }
1346
+ if (!isThemeId(themeId)) {
1347
+ return;
1348
+ }
1349
+ document.documentElement.setAttribute("data-theme", themeId);
1350
+ localStorage.setItem(STORAGE_KEY, themeId);
1351
+ }
1352
+ function readStoredTheme() {
1353
+ if (typeof window === "undefined") {
1354
+ return DEFAULT_THEME_ID;
1355
+ }
1356
+ const stored = localStorage.getItem(STORAGE_KEY);
1357
+ return stored && isThemeId(stored) ? stored : DEFAULT_THEME_ID;
1358
+ }
1359
+
1360
+ // src/components/ui/ThemeDomSync.tsx
1361
+ function ThemeDomSync() {
1362
+ useLayoutEffect(() => {
1363
+ persistTheme(readStoredTheme());
1364
+ }, []);
1365
+ return null;
1366
+ }
1367
+
1368
+ // src/components/ui/ThemeSwitcher.tsx
1369
+ import { useEffect, useState } from "react";
1370
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1371
+ function ThemeSwitcher({ className }) {
1372
+ const [themeId, setThemeId] = useState(DEFAULT_THEME_ID);
1373
+ useEffect(() => {
1374
+ const id = readStoredTheme();
1375
+ persistTheme(id);
1376
+ setThemeId(id);
1377
+ }, []);
1378
+ return /* @__PURE__ */ jsxs15("label", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1379
+ /* @__PURE__ */ jsx16("span", { className: "shrink-0 text-xs font-medium text-ph-mutedtext sm:text-sm", children: "Theme" }),
1380
+ /* @__PURE__ */ jsx16(
1381
+ "select",
1382
+ {
1383
+ className: "ph-select max-w-[11rem] !min-h-[2rem] py-1 pl-2.5 pr-8 text-xs sm:max-w-[14rem] sm:text-sm",
1384
+ value: themeId,
1385
+ "aria-label": "Colour theme",
1386
+ onChange: (event) => {
1387
+ const next = event.target.value;
1388
+ persistTheme(next);
1389
+ setThemeId(next);
1390
+ },
1391
+ children: THEME_GROUPS.map((group) => /* @__PURE__ */ jsx16("optgroup", { label: group, children: THEMES.filter((theme) => theme.group === group).map((theme) => /* @__PURE__ */ jsx16("option", { value: theme.id, children: theme.name }, theme.id)) }, group))
1392
+ }
1393
+ )
1394
+ ] });
1395
+ }
1396
+
1397
+ // src/components/ui/Accordion.tsx
1398
+ import { useState as useState2 } from "react";
1399
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1400
+ function Accordion({
1401
+ items,
1402
+ allowMultiple = false,
1403
+ defaultOpen = [],
1404
+ className
1405
+ }) {
1406
+ const [openItems, setOpenItems] = useState2(new Set(defaultOpen));
1407
+ const toggleItem = (id) => {
1408
+ setOpenItems((prev) => {
1409
+ const next = new Set(prev);
1410
+ if (next.has(id)) {
1411
+ next.delete(id);
1412
+ } else {
1413
+ if (!allowMultiple) {
1414
+ next.clear();
1415
+ }
1416
+ next.add(id);
1417
+ }
1418
+ return next;
1419
+ });
1420
+ };
1421
+ return /* @__PURE__ */ jsx17("div", { className: cn("divide-y divide-ph-border rounded-xl border border-ph-border bg-ph-surface", className), children: items.map((item) => {
1422
+ const isOpen = openItems.has(item.id);
1423
+ return /* @__PURE__ */ jsxs16("div", { className: "first:rounded-t-xl last:rounded-b-xl", children: [
1424
+ /* @__PURE__ */ jsxs16(
1425
+ "button",
1426
+ {
1427
+ type: "button",
1428
+ onClick: () => toggleItem(item.id),
1429
+ className: "flex w-full items-center justify-between px-5 py-4 text-left transition hover:bg-ph-muted",
1430
+ children: [
1431
+ /* @__PURE__ */ jsx17("span", { className: "font-semibold text-ph-ink", children: item.title }),
1432
+ /* @__PURE__ */ jsx17(
1433
+ IconChevronDown,
1434
+ {
1435
+ className: cn(
1436
+ "h-5 w-5 text-ph-mutedtext transition-transform duration-200",
1437
+ isOpen && "rotate-180"
1438
+ )
1439
+ }
1440
+ )
1441
+ ]
1442
+ }
1443
+ ),
1444
+ /* @__PURE__ */ jsx17(
1445
+ "div",
1446
+ {
1447
+ className: cn(
1448
+ "grid transition-all duration-200",
1449
+ isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
1450
+ ),
1451
+ children: /* @__PURE__ */ jsx17("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx17("div", { className: "px-5 pb-4 text-ph-subtle", children: item.content }) })
1452
+ }
1453
+ )
1454
+ ] }, item.id);
1455
+ }) });
1456
+ }
1457
+
1458
+ // src/components/ui/SegmentedControl.tsx
1459
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
1460
+ function SegmentedControl({ options, value, onChange, className }) {
1461
+ return /* @__PURE__ */ jsx18(
1462
+ "div",
1463
+ {
1464
+ className: cn(
1465
+ "inline-flex rounded-lg bg-ph-muted p-1",
1466
+ className
1467
+ ),
1468
+ children: options.map((option) => /* @__PURE__ */ jsxs17(
1469
+ "button",
1470
+ {
1471
+ type: "button",
1472
+ "aria-pressed": value === option.value,
1473
+ onClick: () => onChange(option.value),
1474
+ className: cn(
1475
+ "relative flex min-h-11 items-center gap-1.5 rounded-md px-3.5 py-1.5 text-sm font-medium transition-all sm:min-h-9",
1476
+ value === option.value ? "bg-ph-surface text-ph-ink shadow-ph" : "text-ph-subtle hover:text-ph-ink"
1477
+ ),
1478
+ children: [
1479
+ option.icon && /* @__PURE__ */ jsx18("span", { className: "h-4 w-4", children: option.icon }),
1480
+ option.label
1481
+ ]
1482
+ },
1483
+ option.value
1484
+ ))
1485
+ }
1486
+ );
1487
+ }
1488
+
1489
+ // src/components/ui/CommandPalette.tsx
1490
+ import { useState as useState3, useEffect as useEffect2, useRef as useRef2 } from "react";
1491
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1492
+ function CommandPalette({
1493
+ items,
1494
+ isOpen,
1495
+ onClose,
1496
+ placeholder = "Type a command or search...",
1497
+ className,
1498
+ id,
1499
+ dataTest,
1500
+ inputId,
1501
+ inputDataTest
1502
+ }) {
1503
+ const [query, setQuery] = useState3("");
1504
+ const [selectedIndex, setSelectedIndex] = useState3(0);
1505
+ const inputRef = useRef2(null);
1506
+ const panelRef = useRef2(null);
1507
+ const previousFocusRef = useRef2(null);
1508
+ const filtered = items.filter(
1509
+ (item) => item.label.toLowerCase().includes(query.toLowerCase())
1510
+ );
1511
+ useEffect2(() => {
1512
+ var _a;
1513
+ if (!isOpen) return;
1514
+ previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1515
+ setQuery("");
1516
+ setSelectedIndex(0);
1517
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
1518
+ return () => {
1519
+ var _a2;
1520
+ return (_a2 = previousFocusRef.current) == null ? void 0 : _a2.focus();
1521
+ };
1522
+ }, [isOpen]);
1523
+ useEffect2(() => {
1524
+ const handleKeyDown = (e) => {
1525
+ var _a, _b;
1526
+ if (!isOpen) return;
1527
+ switch (e.key) {
1528
+ case "ArrowDown":
1529
+ if (!filtered.length) break;
1530
+ e.preventDefault();
1531
+ setSelectedIndex((i) => (i + 1) % filtered.length);
1532
+ break;
1533
+ case "ArrowUp":
1534
+ if (!filtered.length) break;
1535
+ e.preventDefault();
1536
+ setSelectedIndex((i) => (i - 1 + filtered.length) % filtered.length);
1537
+ break;
1538
+ case "Enter":
1539
+ e.preventDefault();
1540
+ (_a = filtered[selectedIndex]) == null ? void 0 : _a.onSelect();
1541
+ onClose();
1542
+ break;
1543
+ case "Escape":
1544
+ onClose();
1545
+ break;
1546
+ case "Tab": {
1547
+ const focusable = (_b = panelRef.current) == null ? void 0 : _b.querySelectorAll(
1548
+ 'input, button, [href], [tabindex]:not([tabindex="-1"])'
1549
+ );
1550
+ if (!(focusable == null ? void 0 : focusable.length)) break;
1551
+ const first = focusable[0];
1552
+ const last = focusable[focusable.length - 1];
1553
+ if (e.shiftKey && document.activeElement === first) {
1554
+ e.preventDefault();
1555
+ last.focus();
1556
+ } else if (!e.shiftKey && document.activeElement === last) {
1557
+ e.preventDefault();
1558
+ first.focus();
1559
+ }
1560
+ break;
1561
+ }
1562
+ }
1563
+ };
1564
+ window.addEventListener("keydown", handleKeyDown);
1565
+ return () => window.removeEventListener("keydown", handleKeyDown);
1566
+ }, [isOpen, filtered, selectedIndex, onClose]);
1567
+ if (!isOpen) return null;
1568
+ return /* @__PURE__ */ jsx19(
1569
+ "div",
1570
+ {
1571
+ id,
1572
+ "data-test": dataTest,
1573
+ className: "fixed inset-0 z-50 flex items-start justify-center bg-black/40 pt-[20vh] backdrop-blur-sm",
1574
+ onMouseDown: (event) => {
1575
+ if (event.target === event.currentTarget) onClose();
1576
+ },
1577
+ children: /* @__PURE__ */ jsxs18(
1578
+ "div",
1579
+ {
1580
+ ref: panelRef,
1581
+ role: "dialog",
1582
+ "aria-modal": "true",
1583
+ "aria-label": "Command palette",
1584
+ className: cn(
1585
+ "w-full max-w-xl overflow-hidden rounded-xl border border-ph-border bg-ph-surface shadow-ph-md",
1586
+ className
1587
+ ),
1588
+ children: [
1589
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
1590
+ /* @__PURE__ */ jsx19(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
1591
+ /* @__PURE__ */ jsx19(
1592
+ "input",
1593
+ {
1594
+ ref: inputRef,
1595
+ id: inputId,
1596
+ "data-test": inputDataTest,
1597
+ type: "text",
1598
+ "aria-label": "Search commands",
1599
+ value: query,
1600
+ onChange: (e) => {
1601
+ setQuery(e.target.value);
1602
+ setSelectedIndex(0);
1603
+ },
1604
+ placeholder,
1605
+ className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
1606
+ }
1607
+ ),
1608
+ /* @__PURE__ */ jsx19("kbd", { className: "rounded border border-ph-border bg-ph-muted px-1.5 py-0.5 text-xs text-ph-mutedtext", children: "ESC" })
1609
+ ] }),
1610
+ /* @__PURE__ */ jsx19("div", { className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ jsxs18(
1611
+ "button",
1612
+ {
1613
+ type: "button",
1614
+ id: `command-${item.id}`,
1615
+ "data-test": `command-${item.id}`,
1616
+ onClick: () => {
1617
+ item.onSelect();
1618
+ onClose();
1619
+ },
1620
+ onMouseEnter: () => setSelectedIndex(index),
1621
+ className: cn(
1622
+ "flex w-full items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
1623
+ index === selectedIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
1624
+ ),
1625
+ children: [
1626
+ item.icon && /* @__PURE__ */ jsx19("span", { className: "h-5 w-5", children: item.icon }),
1627
+ /* @__PURE__ */ jsx19("span", { className: "flex-1", children: item.label }),
1628
+ item.shortcut && /* @__PURE__ */ jsx19("kbd", { className: "rounded border border-ph-border bg-ph-surface px-1.5 py-0.5 text-xs text-ph-mutedtext", children: item.shortcut })
1629
+ ]
1630
+ },
1631
+ item.id
1632
+ )) })
1633
+ ]
1634
+ }
1635
+ )
1636
+ }
1637
+ );
1638
+ }
1639
+
1640
+ // src/components/ui/Calendar.tsx
1641
+ import { useState as useState4 } from "react";
1642
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
1643
+ function Calendar({ value, onChange, className }) {
1644
+ const [currentMonth, setCurrentMonth] = useState4(value || /* @__PURE__ */ new Date());
1645
+ const today = /* @__PURE__ */ new Date();
1646
+ const year = currentMonth.getFullYear();
1647
+ const month = currentMonth.getMonth();
1648
+ const firstDay = new Date(year, month, 1).getDay();
1649
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
1650
+ const prevMonth = () => setCurrentMonth(new Date(year, month - 1, 1));
1651
+ const nextMonth = () => setCurrentMonth(new Date(year, month + 1, 1));
1652
+ const monthNames = [
1653
+ "January",
1654
+ "February",
1655
+ "March",
1656
+ "April",
1657
+ "May",
1658
+ "June",
1659
+ "July",
1660
+ "August",
1661
+ "September",
1662
+ "October",
1663
+ "November",
1664
+ "December"
1665
+ ];
1666
+ const weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
1667
+ const isSelected = (day) => {
1668
+ if (!value) return false;
1669
+ return value.getDate() === day && value.getMonth() === month && value.getFullYear() === year;
1670
+ };
1671
+ const isToday = (day) => {
1672
+ return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
1673
+ };
1674
+ const handleSelect = (day) => {
1675
+ onChange == null ? void 0 : onChange(new Date(year, month, day));
1676
+ };
1677
+ const days = [];
1678
+ for (let i = 0; i < firstDay; i++) {
1679
+ days.push(null);
1680
+ }
1681
+ for (let i = 1; i <= daysInMonth; i++) {
1682
+ days.push(i);
1683
+ }
1684
+ return /* @__PURE__ */ jsxs19("div", { className: cn("w-[280px] rounded-xl border border-ph-border bg-ph-surface p-4 shadow-ph", className), children: [
1685
+ /* @__PURE__ */ jsxs19("div", { className: "mb-4 flex items-center justify-between", children: [
1686
+ /* @__PURE__ */ jsx20(
1687
+ "button",
1688
+ {
1689
+ type: "button",
1690
+ onClick: prevMonth,
1691
+ "aria-label": "Previous month",
1692
+ className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
1693
+ children: /* @__PURE__ */ jsx20(IconChevronLeft, { className: "h-5 w-5", "aria-hidden": true })
1694
+ }
1695
+ ),
1696
+ /* @__PURE__ */ jsxs19("span", { className: "text-sm font-semibold text-ph-ink", children: [
1697
+ monthNames[month],
1698
+ " ",
1699
+ year
1700
+ ] }),
1701
+ /* @__PURE__ */ jsx20(
1702
+ "button",
1703
+ {
1704
+ type: "button",
1705
+ onClick: nextMonth,
1706
+ "aria-label": "Next month",
1707
+ className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
1708
+ children: /* @__PURE__ */ jsx20(IconChevronRight, { className: "h-5 w-5", "aria-hidden": true })
1709
+ }
1710
+ )
1711
+ ] }),
1712
+ /* @__PURE__ */ jsxs19("div", { className: "grid grid-cols-7 gap-1", children: [
1713
+ weekDays.map((day) => /* @__PURE__ */ jsx20("div", { className: "py-1 text-center text-xs font-medium text-ph-mutedtext", children: day }, day)),
1714
+ days.map((day, index) => /* @__PURE__ */ jsx20("div", { className: "aspect-square", children: day && /* @__PURE__ */ jsx20(
1715
+ "button",
1716
+ {
1717
+ type: "button",
1718
+ onClick: () => handleSelect(day),
1719
+ className: cn(
1720
+ "flex h-full w-full items-center justify-center rounded-lg text-sm transition-colors",
1721
+ isSelected(day) ? "bg-ph-brand font-semibold text-[var(--ph-on-accent)] shadow-ph" : isToday(day) ? "bg-ph-muted font-semibold text-ph-brand ring-1 ring-ph-brand/30" : "text-ph-ink hover:bg-ph-muted"
1722
+ ),
1723
+ children: day
1724
+ }
1725
+ ) }, index))
1726
+ ] })
1727
+ ] });
1728
+ }
1729
+
1730
+ // src/components/ui/EmptyState.tsx
1731
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
1732
+ function EmptyState({ icon, title, description, action, className }) {
1733
+ return /* @__PURE__ */ jsxs20(
1734
+ "div",
1735
+ {
1736
+ className: cn(
1737
+ "flex flex-col items-center justify-center rounded-xl border border-dashed border-ph-border bg-ph-muted/50 px-8 py-16 text-center",
1738
+ className
1739
+ ),
1740
+ children: [
1741
+ icon && /* @__PURE__ */ jsx21("div", { className: "mb-4 flex h-14 w-14 items-center justify-center rounded-full bg-ph-muted text-ph-mutedtext", children: icon }),
1742
+ /* @__PURE__ */ jsx21("h3", { className: "text-base font-semibold text-ph-ink", children: title }),
1743
+ description && /* @__PURE__ */ jsx21("p", { className: "mt-1 max-w-sm text-sm text-ph-subtle", children: description }),
1744
+ action && /* @__PURE__ */ jsx21("div", { className: "mt-4", children: action })
1745
+ ]
1746
+ }
1747
+ );
1748
+ }
1749
+
1750
+ // src/components/ui/FilterChips.tsx
1751
+ import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
1752
+ function FilterChips({
1753
+ chips,
1754
+ onToggle,
1755
+ onRemove,
1756
+ className,
1757
+ "aria-label": ariaLabel = "Applied filters"
1758
+ }) {
1759
+ return /* @__PURE__ */ jsx22("div", { className: cn("ph-filter-chips", className), role: "group", "aria-label": ariaLabel, children: chips.map((chip) => {
1760
+ var _a;
1761
+ const label = (_a = chip.removeLabel) != null ? _a : getChipText(chip);
1762
+ const content = /* @__PURE__ */ jsxs21(Fragment3, { children: [
1763
+ /* @__PURE__ */ jsx22("span", { className: "ph-filter-chip__label", children: chip.label }),
1764
+ chip.value != null ? /* @__PURE__ */ jsx22("span", { className: "ph-filter-chip__value", children: chip.value }) : null
1765
+ ] });
1766
+ return /* @__PURE__ */ jsxs21(
1767
+ "span",
1768
+ {
1769
+ className: cn("ph-filter-chip", chip.active && "ph-filter-chip--active"),
1770
+ "data-state": chip.active ? "on" : "off",
1771
+ children: [
1772
+ onToggle ? /* @__PURE__ */ jsx22(
1773
+ "button",
1774
+ {
1775
+ type: "button",
1776
+ className: "ph-filter-chip__main",
1777
+ "aria-pressed": Boolean(chip.active),
1778
+ onClick: () => onToggle(chip.id),
1779
+ children: content
1780
+ }
1781
+ ) : /* @__PURE__ */ jsx22("span", { className: "ph-filter-chip__main", children: content }),
1782
+ chip.active && onRemove ? /* @__PURE__ */ jsx22(
1783
+ "button",
1784
+ {
1785
+ type: "button",
1786
+ className: "ph-filter-chip__remove",
1787
+ "aria-label": `Remove ${label} filter`,
1788
+ onClick: () => onRemove(chip.id),
1789
+ children: /* @__PURE__ */ jsx22(IconClose, { className: "h-3 w-3", "aria-hidden": true })
1790
+ }
1791
+ ) : null
1792
+ ]
1793
+ },
1794
+ chip.id
1795
+ );
1796
+ }) });
1797
+ }
1798
+ function getChipText(chip) {
1799
+ const label = typeof chip.label === "string" || typeof chip.label === "number" ? String(chip.label) : chip.id;
1800
+ const value = typeof chip.value === "string" || typeof chip.value === "number" ? String(chip.value) : null;
1801
+ return value ? `${label}: ${value}` : label;
1802
+ }
1803
+
1804
+ // src/components/ui/FilterBar.tsx
1805
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
1806
+ function FilterBar(_a) {
1807
+ var _b = _a, {
1808
+ children,
1809
+ label = "Filters and sorting",
1810
+ onClear,
1811
+ clearLabel = "Clear all",
1812
+ resultCount,
1813
+ className
1814
+ } = _b, props = __objRest(_b, [
1815
+ "children",
1816
+ "label",
1817
+ "onClear",
1818
+ "clearLabel",
1819
+ "resultCount",
1820
+ "className"
1821
+ ]);
1822
+ return /* @__PURE__ */ jsxs22("div", __spreadProps(__spreadValues({ className: cn("ph-filter-bar", className) }, props), { children: [
1823
+ /* @__PURE__ */ jsxs22("div", { className: "ph-filter-bar__controls", role: "group", "aria-label": label, children: [
1824
+ children,
1825
+ onClear ? /* @__PURE__ */ jsx23("button", { type: "button", className: "ph-filter-bar__clear", onClick: onClear, children: clearLabel }) : null
1826
+ ] }),
1827
+ resultCount != null ? /* @__PURE__ */ jsx23("output", { className: "ph-filter-bar__results", "aria-live": "polite", children: resultCount }) : null
1828
+ ] }));
1829
+ }
1830
+ function FilterMenu({
1831
+ label,
1832
+ value,
1833
+ options,
1834
+ onValueChange,
1835
+ placeholder = "Any",
1836
+ align = "start",
1837
+ disabled,
1838
+ className
1839
+ }) {
1840
+ var _a;
1841
+ const selected = options.find((option) => option.value === value);
1842
+ const displayValue = (_a = selected == null ? void 0 : selected.label) != null ? _a : placeholder;
1843
+ const accessibleValue = selected ? getOptionText(selected) : String(placeholder);
1844
+ return /* @__PURE__ */ jsx23(
1845
+ DropdownMenu,
1846
+ {
1847
+ "aria-label": `${label}: ${accessibleValue}`,
1848
+ align,
1849
+ disabled,
1850
+ className,
1851
+ trigger: /* @__PURE__ */ jsxs22("span", { className: cn("ph-filter-menu-trigger", selected && "ph-filter-menu-trigger--active"), children: [
1852
+ /* @__PURE__ */ jsx23(IconTuning, { className: "h-3.5 w-3.5", "aria-hidden": true }),
1853
+ /* @__PURE__ */ jsx23("span", { className: "ph-filter-menu-trigger__label", children: label }),
1854
+ /* @__PURE__ */ jsx23("span", { className: "ph-filter-menu-trigger__value", children: displayValue })
1855
+ ] }),
1856
+ children: /* @__PURE__ */ jsx23(DropdownRadioGroup, { value, onValueChange, children: options.map((option) => /* @__PURE__ */ jsx23(
1857
+ DropdownRadioItem,
1858
+ {
1859
+ value: option.value,
1860
+ textValue: getOptionText(option),
1861
+ disabled: option.disabled,
1862
+ children: option.label
1863
+ },
1864
+ option.value
1865
+ )) })
1866
+ }
1867
+ );
1868
+ }
1869
+ function SortMenu({
1870
+ label,
1871
+ value,
1872
+ options,
1873
+ onValueChange,
1874
+ direction = "descending",
1875
+ align = "end",
1876
+ disabled,
1877
+ className
1878
+ }) {
1879
+ const selected = options.find((option) => option.value === value);
1880
+ return /* @__PURE__ */ jsx23(
1881
+ DropdownMenu,
1882
+ {
1883
+ "aria-label": `${label}: ${selected ? getOptionText(selected) : "Choose sort order"}`,
1884
+ align,
1885
+ disabled,
1886
+ className,
1887
+ trigger: /* @__PURE__ */ jsxs22("span", { className: "ph-filter-menu-trigger ph-sort-menu-trigger", children: [
1888
+ /* @__PURE__ */ jsx23(
1889
+ IconArrowDown,
1890
+ {
1891
+ className: cn("h-3.5 w-3.5", direction === "ascending" && "rotate-180"),
1892
+ "aria-hidden": true
1893
+ }
1894
+ ),
1895
+ /* @__PURE__ */ jsx23("span", { className: "ph-filter-menu-trigger__label", children: label }),
1896
+ selected ? /* @__PURE__ */ jsx23("span", { className: "ph-filter-menu-trigger__value", children: selected.label }) : null
1897
+ ] }),
1898
+ children: /* @__PURE__ */ jsx23(DropdownRadioGroup, { value, onValueChange, children: options.map((option) => /* @__PURE__ */ jsx23(
1899
+ DropdownRadioItem,
1900
+ {
1901
+ value: option.value,
1902
+ textValue: getOptionText(option),
1903
+ disabled: option.disabled,
1904
+ children: option.label
1905
+ },
1906
+ option.value
1907
+ )) })
1908
+ }
1909
+ );
1910
+ }
1911
+ function getOptionText(option) {
1912
+ if (option.textValue) return option.textValue;
1913
+ if (typeof option.label === "string" || typeof option.label === "number") return String(option.label);
1914
+ return option.value;
1915
+ }
1916
+
1917
+ // src/components/ui/FilterControls.tsx
1918
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
1919
+ function FilterControls(_a) {
1920
+ var _b = _a, {
1921
+ children,
1922
+ barProps,
1923
+ chipsProps,
1924
+ emptyState,
1925
+ className
1926
+ } = _b, props = __objRest(_b, [
1927
+ "children",
1928
+ "barProps",
1929
+ "chipsProps",
1930
+ "emptyState",
1931
+ "className"
1932
+ ]);
1933
+ const hasChips = Boolean(chipsProps == null ? void 0 : chipsProps.chips.length);
1934
+ return /* @__PURE__ */ jsxs23("div", __spreadProps(__spreadValues({ className: cn("ph-filter-controls", className) }, props), { children: [
1935
+ /* @__PURE__ */ jsx24(FilterBar, __spreadProps(__spreadValues({}, barProps), { children })),
1936
+ hasChips && chipsProps ? /* @__PURE__ */ jsx24(FilterChips, __spreadValues({}, chipsProps)) : emptyState != null ? emptyState : null
1937
+ ] }));
1938
+ }
1939
+
1940
+ // src/components/ui/CodeBlock.tsx
1941
+ import { useState as useState5 } from "react";
1942
+ import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
1943
+ function CodeBlock({ code, language = "tsx", filename, className }) {
1944
+ const [copied, setCopied] = useState5(false);
1945
+ const handleCopy = async () => {
1946
+ await navigator.clipboard.writeText(code);
1947
+ setCopied(true);
1948
+ setTimeout(() => setCopied(false), 2e3);
1949
+ };
1950
+ return /* @__PURE__ */ jsxs24("div", { className: cn("overflow-hidden rounded-lg border border-ph-border bg-[#1a1a2e]", className), children: [
1951
+ (filename || language) && /* @__PURE__ */ jsxs24("div", { className: "flex items-center justify-between border-b border-white/10 px-4 py-2", children: [
1952
+ /* @__PURE__ */ jsxs24("div", { className: "flex items-center gap-2", children: [
1953
+ /* @__PURE__ */ jsxs24("div", { className: "flex gap-1.5", children: [
1954
+ /* @__PURE__ */ jsx25("div", { className: "h-3 w-3 rounded-full bg-red-400" }),
1955
+ /* @__PURE__ */ jsx25("div", { className: "h-3 w-3 rounded-full bg-amber-400" }),
1956
+ /* @__PURE__ */ jsx25("div", { className: "h-3 w-3 rounded-full bg-emerald-400" })
1957
+ ] }),
1958
+ filename && /* @__PURE__ */ jsx25("span", { className: "ml-2 text-xs text-white/60", children: filename })
1959
+ ] }),
1960
+ /* @__PURE__ */ jsx25(
1961
+ "button",
1962
+ {
1963
+ type: "button",
1964
+ onClick: handleCopy,
1965
+ className: "text-xs text-white/60 transition hover:text-white",
1966
+ children: copied ? "Copied!" : "Copy"
1967
+ }
1968
+ )
1969
+ ] }),
1970
+ /* @__PURE__ */ jsx25("pre", { className: "overflow-x-auto p-4 text-sm leading-relaxed", children: /* @__PURE__ */ jsx25("code", { className: "font-mono text-[#e4e4e7]", children: code }) })
1971
+ ] });
1972
+ }
1973
+
1974
+ // src/components/ui/ComponentDocs.tsx
1975
+ import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
1976
+ function ComponentDocs({ title = "Props & variants", rows, defaultOpen = false, className }) {
1977
+ return /* @__PURE__ */ jsxs25("details", { className: cn("ph-panel group overflow-hidden p-0", className), open: defaultOpen, children: [
1978
+ /* @__PURE__ */ jsxs25("summary", { className: "flex cursor-pointer list-none items-center justify-between gap-4 border-b border-ph-border px-4 py-3 transition hover:bg-ph-muted/60 [&::-webkit-details-marker]:hidden", children: [
1979
+ /* @__PURE__ */ jsx26("h3", { className: "text-xs font-semibold uppercase tracking-wider text-ph-mutedtext", children: title }),
1980
+ /* @__PURE__ */ jsxs25("span", { className: "rounded-full border border-ph-border bg-ph-surface px-2 py-1 text-[10px] font-semibold uppercase tracking-wider text-ph-mutedtext transition group-open:bg-ph-brand group-open:text-white", children: [
1981
+ /* @__PURE__ */ jsx26("span", { className: "group-open:hidden", children: "Show" }),
1982
+ /* @__PURE__ */ jsx26("span", { className: "hidden group-open:inline", children: "Hide" })
1983
+ ] })
1984
+ ] }),
1985
+ /* @__PURE__ */ jsx26("div", { className: "overflow-x-auto border-t border-ph-border", children: /* @__PURE__ */ jsxs25("table", { className: "w-full text-left text-sm", children: [
1986
+ /* @__PURE__ */ jsx26("thead", { className: "bg-ph-muted text-xs uppercase tracking-wider text-ph-mutedtext", children: /* @__PURE__ */ jsxs25("tr", { children: [
1987
+ /* @__PURE__ */ jsx26("th", { className: "px-4 py-2 font-semibold", children: "Prop" }),
1988
+ /* @__PURE__ */ jsx26("th", { className: "px-4 py-2 font-semibold", children: "Type" }),
1989
+ /* @__PURE__ */ jsx26("th", { className: "px-4 py-2 font-semibold", children: "Default" }),
1990
+ /* @__PURE__ */ jsx26("th", { className: "px-4 py-2 font-semibold", children: "Use" })
1991
+ ] }) }),
1992
+ /* @__PURE__ */ jsx26("tbody", { className: "divide-y divide-ph-border", children: rows.map((row) => {
1993
+ var _a, _b;
1994
+ return /* @__PURE__ */ jsxs25("tr", { children: [
1995
+ /* @__PURE__ */ jsx26("td", { className: "px-4 py-3 align-top font-mono text-xs text-ph-ink", children: row.name }),
1996
+ /* @__PURE__ */ jsx26("td", { className: "px-4 py-3 align-top font-mono text-xs text-ph-subtle", children: row.type }),
1997
+ /* @__PURE__ */ jsx26("td", { className: "px-4 py-3 align-top font-mono text-xs text-ph-subtle", children: (_a = row.defaultValue) != null ? _a : "-" }),
1998
+ /* @__PURE__ */ jsx26("td", { className: "px-4 py-3 align-top text-ph-subtle", children: (_b = row.description) != null ? _b : /* @__PURE__ */ jsx26("span", { className: "text-ph-mutedtext", children: "\u2014" }) })
1999
+ ] }, row.name);
2000
+ }) })
2001
+ ] }) })
2002
+ ] });
2003
+ }
2004
+
2005
+ // src/components/ui/ShowcaseWrapper.tsx
2006
+ import { useState as useState6 } from "react";
2007
+ import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
2008
+ function ShowcaseWrapper({
2009
+ id,
2010
+ title,
2011
+ description,
2012
+ docs,
2013
+ code,
2014
+ filename = "Example.tsx",
2015
+ children,
2016
+ className
2017
+ }) {
2018
+ var _a;
2019
+ const [showCode, setShowCode] = useState6(false);
2020
+ const fallbackId = (_a = titleIdMap[title]) != null ? _a : title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2021
+ return /* @__PURE__ */ jsxs26("section", { id: id != null ? id : fallbackId, className: cn("scroll-mt-20", className), children: [
2022
+ /* @__PURE__ */ jsxs26("div", { className: "ph-h2-rule mb-8", children: [
2023
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-1.5", children: [
2024
+ /* @__PURE__ */ jsx27("h2", { children: title }),
2025
+ /* @__PURE__ */ jsx27(
2026
+ "button",
2027
+ {
2028
+ type: "button",
2029
+ onClick: () => setShowCode(!showCode),
2030
+ className: cn(
2031
+ "flex h-10 w-10 items-center justify-center rounded-full border transition-all",
2032
+ showCode ? "border-ph-brand bg-ph-brand text-[var(--ph-on-accent)] shadow-lg shadow-ph-brand/25" : "border-ph-border bg-ph-surface text-ph-subtle hover:border-ph-brand hover:text-ph-brand"
2033
+ ),
2034
+ title: showCode ? "Hide code" : "Show code",
2035
+ "aria-label": showCode ? "Hide code" : "Show code",
2036
+ children: /* @__PURE__ */ jsx27(IconCodePreview, { className: "h-5 w-5", "aria-hidden": true })
2037
+ }
2038
+ )
2039
+ ] }),
2040
+ /* @__PURE__ */ jsx27("hr", {})
2041
+ ] }),
2042
+ description && /* @__PURE__ */ jsx27("p", { className: "mb-6 text-sm text-ph-subtle", children: description }),
2043
+ docs && /* @__PURE__ */ jsx27("div", { className: "mb-6", children: docs }),
2044
+ /* @__PURE__ */ jsxs26(
2045
+ "div",
2046
+ {
2047
+ className: cn(
2048
+ "gap-6",
2049
+ showCode ? "lg:grid lg:grid-cols-[1fr,minmax(360px,420px)]" : "block"
2050
+ ),
2051
+ children: [
2052
+ /* @__PURE__ */ jsx27("div", { className: cn("min-w-0", showCode && "lg:pr-2"), children }),
2053
+ /* @__PURE__ */ jsx27(
2054
+ "div",
2055
+ {
2056
+ className: cn(
2057
+ "transition-all duration-300",
2058
+ showCode ? "block opacity-100" : "hidden opacity-0 lg:hidden"
2059
+ ),
2060
+ children: /* @__PURE__ */ jsx27("div", { className: "sticky top-20", children: /* @__PURE__ */ jsx27(CodeBlock, { code, filename }) })
2061
+ }
2062
+ )
2063
+ ]
2064
+ }
2065
+ )
2066
+ ] });
2067
+ }
2068
+ var titleIdMap = {
2069
+ "Icons": "icons",
2070
+ "Colour tokens": "colors",
2071
+ "Buttons": "buttons",
2072
+ "Badges": "badges",
2073
+ "Alerts": "alerts",
2074
+ "Toasts": "toasts",
2075
+ "Cards": "cards",
2076
+ "Forms": "forms",
2077
+ "Inputs & Forms": "forms",
2078
+ "Tables": "tables",
2079
+ "Accordion": "accordion",
2080
+ "Calendar": "calendar",
2081
+ "Hover Card": "hovercard",
2082
+ "Modals": "modals",
2083
+ "Drawers": "drawers",
2084
+ "Navigation chrome": "navigation",
2085
+ "Navigation utilities": "utilities",
2086
+ "Stepper": "stepper",
2087
+ "Command Palette": "command",
2088
+ "Filter Chips": "filters",
2089
+ "Empty State": "emptystate",
2090
+ "Charts (PostHog-style)": "charts",
2091
+ "Dashboard shells": "dashboard",
2092
+ "Tabs": "tabs",
2093
+ "Dropdowns": "dropdowns",
2094
+ "Progress & loading": "progress",
2095
+ "Tooltip": "tooltip",
2096
+ "Avatars": "avatars",
2097
+ "Stats & conversational UI": "stats",
2098
+ "Timeline": "timeline",
2099
+ "Countdown motif": "countdown",
2100
+ "Keyboard glyphs": "kbd",
2101
+ "Icon swap": "swap",
2102
+ "Stacked surfaces": "stack",
2103
+ "Diff slider": "diff",
2104
+ "Badge hotspots": "indicator",
2105
+ "Terminal capture": "code-mockup"
2106
+ };
2107
+
2108
+ // src/components/ui/CollapsibleSection.tsx
2109
+ import { useId as useId5, useState as useState7 } from "react";
2110
+ import { jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
2111
+ function CollapsibleSection({ title, children, defaultOpen = true, id }) {
2112
+ const [isOpen, setIsOpen] = useState7(defaultOpen);
2113
+ const generatedId = useId5();
2114
+ const contentId = `${id != null ? id : generatedId}-content`;
2115
+ return /* @__PURE__ */ jsxs27("section", { id, className: "scroll-mt-20", children: [
2116
+ /* @__PURE__ */ jsxs27(
2117
+ "button",
2118
+ {
2119
+ type: "button",
2120
+ onClick: () => setIsOpen(!isOpen),
2121
+ "aria-expanded": isOpen,
2122
+ "aria-controls": contentId,
2123
+ className: "mb-6 flex w-full items-center justify-between rounded-lg border border-ph-border bg-ph-muted px-5 py-4 text-left transition hover:bg-ph-muted/80",
2124
+ children: [
2125
+ /* @__PURE__ */ jsx28("span", { className: "text-lg font-bold text-ph-ink", children: title }),
2126
+ /* @__PURE__ */ jsx28(
2127
+ IconChevronDown,
2128
+ {
2129
+ className: cn(
2130
+ "h-5 w-5 text-ph-subtle transition-transform duration-200",
2131
+ isOpen && "rotate-180"
2132
+ ),
2133
+ "aria-hidden": true
2134
+ }
2135
+ )
2136
+ ]
2137
+ }
2138
+ ),
2139
+ /* @__PURE__ */ jsx28(
2140
+ "div",
2141
+ {
2142
+ id: contentId,
2143
+ "aria-hidden": !isOpen,
2144
+ className: cn(
2145
+ "overflow-hidden transition-all duration-300",
2146
+ isOpen ? "max-h-[50000px] opacity-100" : "max-h-0 opacity-0"
2147
+ ),
2148
+ children
2149
+ }
2150
+ )
2151
+ ] });
2152
+ }
2153
+
2154
+ // src/components/ui/Typography.tsx
2155
+ import { jsx as jsx29 } from "react/jsx-runtime";
2156
+ var toneMap2 = {
2157
+ default: "text-ph-ink",
2158
+ muted: "text-ph-mutedtext",
2159
+ subtle: "text-ph-subtle",
2160
+ brand: "text-ph-brand",
2161
+ danger: "text-ph-danger",
2162
+ success: "text-ph-success",
2163
+ warning: "text-ph-warning",
2164
+ info: "text-ph-info",
2165
+ inherit: ""
2166
+ };
2167
+ var weightMap = {
2168
+ normal: "font-normal",
2169
+ medium: "font-medium",
2170
+ semibold: "font-semibold",
2171
+ bold: "font-bold",
2172
+ extrabold: "font-extrabold"
2173
+ };
2174
+ function textClass(base, tone, weight, truncate, className) {
2175
+ return cn(base, toneMap2[tone], weight && weightMap[weight], truncate && "truncate", className);
2176
+ }
2177
+ function Display({
2178
+ children,
2179
+ tone = "default",
2180
+ weight,
2181
+ truncate,
2182
+ className
2183
+ }) {
2184
+ return /* @__PURE__ */ jsx29("h1", { className: textClass("ph-hero-title", tone, weight, truncate, className), children });
2185
+ }
2186
+ function SectionTitle({ children, tone = "default", weight, truncate, className }) {
2187
+ return /* @__PURE__ */ jsx29("h2", { className: textClass("ph-section-title", tone, weight, truncate, className), children });
2188
+ }
2189
+ function H1({ children, tone = "default", weight, truncate, className }) {
2190
+ return /* @__PURE__ */ jsx29("h1", { className: textClass("text-3xl font-bold tracking-tight md:text-4xl", tone, weight, truncate, className), children });
2191
+ }
2192
+ function H2({ children, tone = "default", weight, truncate, className }) {
2193
+ return /* @__PURE__ */ jsx29("h2", { className: textClass("text-2xl font-bold tracking-tight", tone, weight, truncate, className), children });
2194
+ }
2195
+ function H3({ children, tone = "default", weight, truncate, className }) {
2196
+ return /* @__PURE__ */ jsx29("h3", { className: textClass("text-xl font-semibold", tone, weight, truncate, className), children });
2197
+ }
2198
+ function H4({ children, tone = "default", weight, truncate, className }) {
2199
+ return /* @__PURE__ */ jsx29("h4", { className: textClass("text-lg font-semibold", tone, weight, truncate, className), children });
2200
+ }
2201
+ function H5({ children, tone = "default", weight, truncate, className }) {
2202
+ return /* @__PURE__ */ jsx29("h5", { className: textClass("text-base font-semibold", tone, weight, truncate, className), children });
2203
+ }
2204
+ function P({ children, tone = "default", weight, truncate, className }) {
2205
+ return /* @__PURE__ */ jsx29("p", { className: textClass("text-base leading-relaxed", tone, weight, truncate, className), children });
2206
+ }
2207
+ function Small({ children, tone = "default", weight, truncate, className }) {
2208
+ return /* @__PURE__ */ jsx29("span", { className: textClass("text-sm leading-relaxed", tone, weight, truncate, className), children });
2209
+ }
2210
+ function Caption({ children, tone = "muted", weight, truncate, className }) {
2211
+ return /* @__PURE__ */ jsx29("span", { className: textClass("text-[11px] font-medium uppercase tracking-wider", tone, weight, truncate, className), children });
2212
+ }
2213
+ function Overline({ children, tone = "muted", weight, truncate, className }) {
2214
+ return /* @__PURE__ */ jsx29("span", { className: textClass("text-[10px] font-bold uppercase tracking-[0.15em]", tone, weight, truncate, className), children });
2215
+ }
2216
+ function Lead({ children, tone = "subtle", weight, truncate, className }) {
2217
+ return /* @__PURE__ */ jsx29("p", { className: textClass("ph-lead", tone, weight, truncate, className), children });
2218
+ }
2219
+ function Mono({ children, tone = "default", weight, truncate, className }) {
2220
+ return /* @__PURE__ */ jsx29("code", { className: textClass("text-sm font-mono leading-relaxed", tone, weight, truncate, className), children });
2221
+ }
2222
+ function Label({ children, tone = "default", weight, truncate, className }) {
2223
+ return /* @__PURE__ */ jsx29("label", { className: textClass("text-sm font-medium", tone, weight, truncate, className), children });
2224
+ }
2225
+
2226
+ // src/components/ui/Avatar.tsx
2227
+ import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
2228
+ var sizeMap4 = {
2229
+ xs: "h-8 w-8 text-[10px]",
2230
+ sm: "h-10 w-10 text-xs",
2231
+ md: "h-12 w-12 text-base",
2232
+ lg: "h-16 w-16 text-xl",
2233
+ xl: "h-24 w-24 text-3xl"
2234
+ };
2235
+ var statusMap = {
2236
+ online: "bg-emerald-500",
2237
+ offline: "bg-ph-mutedtext",
2238
+ away: "bg-amber-400",
2239
+ busy: "bg-ph-danger"
2240
+ };
2241
+ function Avatar(_a) {
2242
+ var _b = _a, {
2243
+ label,
2244
+ icon,
2245
+ size = "md",
2246
+ color = "bg-ph-brand text-white",
2247
+ status,
2248
+ badge,
2249
+ className
2250
+ } = _b, props = __objRest(_b, [
2251
+ "label",
2252
+ "icon",
2253
+ "size",
2254
+ "color",
2255
+ "status",
2256
+ "badge",
2257
+ "className"
2258
+ ]);
2259
+ return /* @__PURE__ */ jsxs28("div", __spreadProps(__spreadValues({ className: cn("relative inline-flex shrink-0", className) }, props), { children: [
2260
+ /* @__PURE__ */ jsx30(
2261
+ "div",
2262
+ {
2263
+ className: cn(
2264
+ "flex items-center justify-center rounded-full border border-ph-border font-bold shadow-ph",
2265
+ sizeMap4[size],
2266
+ color
2267
+ ),
2268
+ children: icon || label
2269
+ }
2270
+ ),
2271
+ status && /* @__PURE__ */ jsx30(
2272
+ "span",
2273
+ {
2274
+ className: cn(
2275
+ "absolute bottom-0 right-1 h-2.5 w-2.5 rounded-full border-2 border-white",
2276
+ statusMap[status]
2277
+ )
2278
+ }
2279
+ ),
2280
+ badge && /* @__PURE__ */ jsx30("span", { className: "absolute -bottom-1 -right-1 flex min-w-[22px] items-center justify-center rounded-full bg-ph-brand px-1.5 py-px text-[10px] font-bold text-white", children: badge })
2281
+ ] }));
2282
+ }
2283
+ function AvatarGroup(_a) {
2284
+ var _b = _a, { children, max, className } = _b, props = __objRest(_b, ["children", "max", "className"]);
2285
+ const items = Array.isArray(children) ? children : [children];
2286
+ const visible = max ? items.slice(0, max) : items;
2287
+ const remaining = max ? items.length - max : 0;
2288
+ return /* @__PURE__ */ jsxs28("div", __spreadProps(__spreadValues({ className: cn("-space-x-3 flex rtl:space-x-reverse", className) }, props), { children: [
2289
+ visible,
2290
+ remaining > 0 && /* @__PURE__ */ jsx30(
2291
+ Avatar,
2292
+ {
2293
+ label: `+${remaining}`,
2294
+ size: "md",
2295
+ color: "bg-ph-toolbar text-ph-subtle"
2296
+ }
2297
+ )
2298
+ ] }));
2299
+ }
2300
+
2301
+ // src/components/ui/Progress.tsx
2302
+ import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
2303
+ var sizeMap5 = {
2304
+ sm: "h-1",
2305
+ md: "h-2",
2306
+ lg: "h-3"
2307
+ };
2308
+ function Progress(_a) {
2309
+ var _b = _a, {
2310
+ value,
2311
+ max = 100,
2312
+ color = "bg-ph-brand",
2313
+ label,
2314
+ showPercentage = false,
2315
+ size = "md",
2316
+ className
2317
+ } = _b, props = __objRest(_b, [
2318
+ "value",
2319
+ "max",
2320
+ "color",
2321
+ "label",
2322
+ "showPercentage",
2323
+ "size",
2324
+ "className"
2325
+ ]);
2326
+ const percentage = Math.min(100, Math.max(0, value / max * 100));
2327
+ return /* @__PURE__ */ jsxs29("div", __spreadProps(__spreadValues({ className: cn("w-full", className) }, props), { children: [
2328
+ (label || showPercentage) && /* @__PURE__ */ jsxs29("div", { className: "mb-1.5 flex justify-between text-sm text-ph-subtle", children: [
2329
+ label && /* @__PURE__ */ jsx31("span", { children: label }),
2330
+ showPercentage && /* @__PURE__ */ jsxs29("span", { className: "tabular-nums", children: [
2331
+ Math.round(percentage),
2332
+ "%"
2333
+ ] })
2334
+ ] }),
2335
+ /* @__PURE__ */ jsx31("div", { className: cn("ph-progress", sizeMap5[size]), children: /* @__PURE__ */ jsx31(
2336
+ "div",
2337
+ {
2338
+ className: cn("ph-progress-bar", color),
2339
+ style: { width: `${percentage}%` },
2340
+ role: "progressbar",
2341
+ "aria-valuenow": value,
2342
+ "aria-valuemin": 0,
2343
+ "aria-valuemax": max
2344
+ }
2345
+ ) })
2346
+ ] }));
2347
+ }
2348
+
2349
+ // src/components/ui/Link.tsx
2350
+ import { forwardRef as forwardRef6 } from "react";
2351
+ import { jsx as jsx32 } from "react/jsx-runtime";
2352
+ var Link = forwardRef6(function Link2(_a, ref) {
2353
+ var _b = _a, {
2354
+ className,
2355
+ disabled = false,
2356
+ children
2357
+ } = _b, props = __objRest(_b, [
2358
+ "className",
2359
+ "disabled",
2360
+ "children"
2361
+ ]);
2362
+ return /* @__PURE__ */ jsx32(
2363
+ "a",
2364
+ __spreadProps(__spreadValues({
2365
+ ref,
2366
+ className: cn(
2367
+ "ph-link",
2368
+ disabled && "ph-link--disabled pointer-events-none opacity-50",
2369
+ className
2370
+ ),
2371
+ tabIndex: disabled ? -1 : void 0,
2372
+ "aria-disabled": disabled || void 0
2373
+ }, props), {
2374
+ children
2375
+ })
2376
+ );
2377
+ });
2378
+ Link.displayName = "Link";
2379
+
2380
+ // src/components/ui/Spinner.tsx
2381
+ import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2382
+ function Spinner(_a) {
2383
+ var _b = _a, { size = "sm", textColored = false, className } = _b, props = __objRest(_b, ["size", "textColored", "className"]);
2384
+ return /* @__PURE__ */ jsx33(
2385
+ "span",
2386
+ __spreadProps(__spreadValues({
2387
+ className: cn(
2388
+ "ph-spinner",
2389
+ `ph-spinner--${size}`,
2390
+ textColored && "ph-spinner--text-colored",
2391
+ className
2392
+ ),
2393
+ role: "status",
2394
+ "aria-label": "Loading"
2395
+ }, props), {
2396
+ children: /* @__PURE__ */ jsxs30("svg", { viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "ph-spinner__svg", children: [
2397
+ /* @__PURE__ */ jsx33("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3", opacity: 0.2 }),
2398
+ /* @__PURE__ */ jsx33("path", { d: "M12 2a10 10 0 0 1 10 10", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" })
2399
+ ] })
2400
+ })
2401
+ );
2402
+ }
2403
+ Spinner.displayName = "Spinner";
2404
+
2405
+ // src/components/ui/Dot.tsx
2406
+ import { jsx as jsx34 } from "react/jsx-runtime";
2407
+ var colorMap = {
2408
+ green: "bg-ph-success",
2409
+ yellow: "bg-ph-warning",
2410
+ red: "bg-ph-danger",
2411
+ blue: "bg-ph-info",
2412
+ gray: "bg-ph-mutedtext"
2413
+ };
2414
+ function Dot(_a) {
2415
+ var _b = _a, { color = "gray", size = "md", className } = _b, props = __objRest(_b, ["color", "size", "className"]);
2416
+ return /* @__PURE__ */ jsx34(
2417
+ "span",
2418
+ __spreadValues({
2419
+ className: cn(
2420
+ "ph-dot inline-block shrink-0 rounded-full",
2421
+ size === "sm" ? "h-1.5 w-1.5" : "h-2.5 w-2.5",
2422
+ colorMap[color],
2423
+ className
2424
+ ),
2425
+ "aria-hidden": "true"
2426
+ }, props)
2427
+ );
2428
+ }
2429
+ Dot.displayName = "Dot";
2430
+
2431
+ // src/components/ui/Chip.tsx
2432
+ import { forwardRef as forwardRef7 } from "react";
2433
+ import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
2434
+ var Chip = forwardRef7(function Chip2(_a, ref) {
2435
+ var _b = _a, {
2436
+ selected = false,
2437
+ onRemove,
2438
+ children,
2439
+ className
2440
+ } = _b, props = __objRest(_b, [
2441
+ "selected",
2442
+ "onRemove",
2443
+ "children",
2444
+ "className"
2445
+ ]);
2446
+ const chipClassName = cn(
2447
+ "ph-chip",
2448
+ selected && "ph-chip--selected",
2449
+ className
2450
+ );
2451
+ if (onRemove) {
2452
+ const removeLabel = typeof children === "string" ? `Remove ${children}` : "Remove";
2453
+ return /* @__PURE__ */ jsxs31("span", { className: chipClassName, children: [
2454
+ /* @__PURE__ */ jsx35(
2455
+ "button",
2456
+ __spreadProps(__spreadValues({
2457
+ ref,
2458
+ type: "button",
2459
+ className: "min-w-0 bg-transparent p-0 text-inherit"
2460
+ }, props), {
2461
+ children: /* @__PURE__ */ jsx35("span", { className: "ph-chip__text", children })
2462
+ })
2463
+ ),
2464
+ /* @__PURE__ */ jsx35(
2465
+ "button",
2466
+ {
2467
+ type: "button",
2468
+ onClick: onRemove,
2469
+ disabled: props.disabled,
2470
+ className: "ph-chip__remove",
2471
+ "aria-label": removeLabel,
2472
+ children: /* @__PURE__ */ jsx35("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx35("path", { d: "M2 2l6 6M8 2l-6 6" }) })
2473
+ }
2474
+ )
2475
+ ] });
2476
+ }
2477
+ return /* @__PURE__ */ jsx35(
2478
+ "button",
2479
+ __spreadProps(__spreadValues({
2480
+ ref,
2481
+ type: "button",
2482
+ className: chipClassName
2483
+ }, props), {
2484
+ children: /* @__PURE__ */ jsx35("span", { className: "ph-chip__text", children })
2485
+ })
2486
+ );
2487
+ });
2488
+ Chip.displayName = "Chip";
2489
+
2490
+ export {
2491
+ Button,
2492
+ Alert,
2493
+ Badge,
2494
+ Card,
2495
+ Kbd,
2496
+ Loader,
2497
+ Skeleton,
2498
+ LoadingState,
2499
+ AuthLayout,
2500
+ AuthCard,
2501
+ AuthDivider,
2502
+ SettingsNav,
2503
+ SettingsLayout,
2504
+ FormField,
2505
+ Input,
2506
+ Select,
2507
+ Textarea,
2508
+ Checkbox,
2509
+ Radio,
2510
+ Toggle,
2511
+ Range,
2512
+ FileUpload,
2513
+ Modal,
2514
+ Panel,
2515
+ SearchInput,
2516
+ SearchGroup,
2517
+ Table,
2518
+ Stat,
2519
+ DEFAULT_THEME_ID,
2520
+ THEMES,
2521
+ THEME_GROUPS,
2522
+ isThemeId,
2523
+ getTheme,
2524
+ THEME_INIT_SCRIPT,
2525
+ persistTheme,
2526
+ readStoredTheme,
2527
+ ThemeDomSync,
2528
+ ThemeSwitcher,
2529
+ Accordion,
2530
+ SegmentedControl,
2531
+ CommandPalette,
2532
+ Calendar,
2533
+ EmptyState,
2534
+ FilterChips,
2535
+ FilterBar,
2536
+ FilterMenu,
2537
+ SortMenu,
2538
+ FilterControls,
2539
+ CodeBlock,
2540
+ ComponentDocs,
2541
+ ShowcaseWrapper,
2542
+ CollapsibleSection,
2543
+ Display,
2544
+ SectionTitle,
2545
+ H1,
2546
+ H2,
2547
+ H3,
2548
+ H4,
2549
+ H5,
2550
+ P,
2551
+ Small,
2552
+ Caption,
2553
+ Overline,
2554
+ Lead,
2555
+ Mono,
2556
+ Label,
2557
+ Avatar,
2558
+ AvatarGroup,
2559
+ Progress,
2560
+ Link,
2561
+ Spinner,
2562
+ Dot,
2563
+ Chip
2564
+ };