@xenide-io/the-old-ui-theme 0.3.2 → 0.4.3

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 (62) hide show
  1. package/dist/chunk-54ZR4VL5.mjs +4641 -0
  2. package/dist/chunk-G53YLHVE.mjs +1023 -0
  3. package/dist/{index-BgG8Homu.d.mts → index-B5NOyoKS.d.mts} +100 -100
  4. package/dist/{index-BgG8Homu.d.ts → index-B5NOyoKS.d.ts} +100 -100
  5. package/dist/index.d.mts +9 -145
  6. package/dist/index.d.ts +9 -145
  7. package/dist/index.js +653 -1111
  8. package/dist/index.mjs +86 -342
  9. package/dist/suite.d.mts +760 -0
  10. package/dist/suite.d.ts +760 -0
  11. package/dist/suite.js +2800 -0
  12. package/dist/suite.mjs +2441 -0
  13. package/dist/ui.d.mts +1 -2
  14. package/dist/ui.d.ts +1 -2
  15. package/dist/ui.js +14 -10
  16. package/dist/ui.mjs +13 -11
  17. package/package.json +43 -24
  18. package/src/components/icons/icons.tsx +0 -2
  19. package/src/components/icons/index.ts +0 -3
  20. package/src/components/sections/IconShowcase.tsx +1 -110
  21. package/src/components/sections/NewComponentsShowcase.tsx +4 -4
  22. package/src/components/sections/SidebarShowcase.tsx +3 -3
  23. package/src/components/sections/SuiteShowcase.tsx +669 -0
  24. package/src/components/ui/ComponentDocs.tsx +2 -2
  25. package/src/components/ui/ContextMenu.tsx +1 -1
  26. package/src/components/ui/Menubar.tsx +1 -1
  27. package/src/components/ui/Sidebar.tsx +10 -8
  28. package/src/styles/suite-skin.css +255 -0
  29. package/src/suite/components/ai-panel.tsx +202 -0
  30. package/src/suite/components/app-switcher.tsx +196 -0
  31. package/src/suite/components/command-palette-host.tsx +62 -0
  32. package/src/suite/components/deferred-chrome.tsx +12 -0
  33. package/src/suite/components/suite-app-layout.tsx +69 -0
  34. package/src/suite/components/suite-bottom-nav.tsx +113 -0
  35. package/src/suite/components/suite-layout.tsx +285 -0
  36. package/src/suite/components/suite-mobile-drawer.tsx +150 -0
  37. package/src/suite/components/suite-mobile-header.tsx +71 -0
  38. package/src/suite/components/suite-notification-bell.tsx +227 -0
  39. package/src/suite/components/suite-settings-mobile-nav.tsx +83 -0
  40. package/src/suite/components/suite-sidebar.tsx +198 -0
  41. package/src/suite/components/suite-skeleton.tsx +191 -0
  42. package/src/suite/components/suite-user-menu.tsx +109 -0
  43. package/src/suite/components/theme-provider.tsx +174 -0
  44. package/src/suite/components/today-calibrating.tsx +95 -0
  45. package/src/suite/components/today-page-frame.tsx +28 -0
  46. package/src/suite/components/today-ui.tsx +370 -0
  47. package/src/suite/icons/app-accents.ts +75 -0
  48. package/src/suite/icons/glyph-parts.tsx +67 -0
  49. package/src/suite/icons/glyphs.ts +203 -0
  50. package/src/suite/icons/index.ts +12 -0
  51. package/src/suite/icons/suite-app-icon.tsx +68 -0
  52. package/src/suite/icons/suite-icon.tsx +93 -0
  53. package/src/suite/index.ts +108 -0
  54. package/src/suite/lib/apps.ts +75 -0
  55. package/src/suite/lib/cn.ts +6 -0
  56. package/src/suite/lib/injected.ts +54 -0
  57. package/src/suite/lib/motion.tsx +48 -0
  58. package/src/suite/lib/use-idle-mount.ts +25 -0
  59. package/dist/chunk-5HSOBJ4F.mjs +0 -5968
  60. package/src/components/icons/lemon-brand-icons.tsx +0 -16
  61. package/src/components/icons/lemon-category-icons.tsx +0 -72
  62. package/src/components/icons/lemon-icons.tsx +0 -57
@@ -0,0 +1,4641 @@
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
+ IconErrorOutline,
16
+ IconExclamation,
17
+ IconInfo,
18
+ IconSearch,
19
+ IconStar,
20
+ IconTuning,
21
+ cn
22
+ } from "./chunk-G53YLHVE.mjs";
23
+ import {
24
+ __objRest,
25
+ __spreadProps,
26
+ __spreadValues
27
+ } from "./chunk-FWCSY2DS.mjs";
28
+
29
+ // src/components/ui/Button.tsx
30
+ import { forwardRef } from "react";
31
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
32
+ var variantClass = {
33
+ primary: "ph-btn-primary",
34
+ secondary: "ph-btn-secondary",
35
+ tertiary: "ph-btn-tertiary",
36
+ signal: "ph-btn-signal",
37
+ accent: "ph-btn-accent",
38
+ neutral: "ph-btn-neutral",
39
+ info: "ph-btn-info",
40
+ success: "ph-btn-success",
41
+ warning: "ph-btn-warning",
42
+ danger: "ph-btn-danger",
43
+ ghost: "ph-btn-ghost",
44
+ link: "ph-btn-link"
45
+ };
46
+ var sizeClass = {
47
+ xs: "ph-btn-xs",
48
+ sm: "ph-btn-sm",
49
+ md: "",
50
+ lg: "ph-btn-lg"
51
+ };
52
+ var shapeClass = {
53
+ default: "",
54
+ circle: "ph-btn-circle",
55
+ square: "ph-btn-square",
56
+ wide: "ph-btn-wide"
57
+ };
58
+ var Button = forwardRef(function Button2(_a, ref) {
59
+ var _b = _a, {
60
+ variant = "secondary",
61
+ size = "md",
62
+ shape = "default",
63
+ outline = false,
64
+ split = false,
65
+ icon,
66
+ sideIcon,
67
+ loading = false,
68
+ loadingLabel,
69
+ className,
70
+ children,
71
+ type = "button",
72
+ disabled
73
+ } = _b, props = __objRest(_b, [
74
+ "variant",
75
+ "size",
76
+ "shape",
77
+ "outline",
78
+ "split",
79
+ "icon",
80
+ "sideIcon",
81
+ "loading",
82
+ "loadingLabel",
83
+ "className",
84
+ "children",
85
+ "type",
86
+ "disabled"
87
+ ]);
88
+ const usesLemonChrome = !["tertiary", "ghost", "link"].includes(variant);
89
+ const label = loadingLabel != null ? loadingLabel : children;
90
+ const leadingIcon = loading ? /* @__PURE__ */ jsx("span", { className: "ph-btn-spinner", "aria-hidden": true }) : icon;
91
+ const content = usesLemonChrome ? /* @__PURE__ */ jsx(ButtonChrome, { label, icon: leadingIcon, sideIcon, split }) : /* @__PURE__ */ jsxs(Fragment, { children: [
92
+ leadingIcon != null ? /* @__PURE__ */ jsx("span", { className: "ph-btn-icon", children: leadingIcon }) : null,
93
+ label != null ? /* @__PURE__ */ jsx("span", { className: "ph-btn-label", children: label }) : null,
94
+ split ? /* @__PURE__ */ jsx("span", { className: "ph-btn-split-divider", "aria-hidden": true }) : null,
95
+ sideIcon != null ? /* @__PURE__ */ jsx("span", { className: "ph-btn-side-icon", children: sideIcon }) : null
96
+ ] });
97
+ return /* @__PURE__ */ jsx(
98
+ "button",
99
+ __spreadProps(__spreadValues({
100
+ ref,
101
+ type,
102
+ disabled: disabled || loading,
103
+ "aria-busy": loading || void 0,
104
+ className: cn(
105
+ "ph-btn",
106
+ usesLemonChrome && "ph-btn-raised",
107
+ outline && "ph-btn-outline",
108
+ variantClass[variant],
109
+ sizeClass[size],
110
+ shapeClass[shape],
111
+ split && "ph-btn-split",
112
+ className
113
+ )
114
+ }, props), {
115
+ children: content
116
+ })
117
+ );
118
+ });
119
+ Button.displayName = "Button";
120
+
121
+ // src/components/ui/Alert.tsx
122
+ import { forwardRef as forwardRef2 } from "react";
123
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
124
+ var statusConfig = {
125
+ info: { icon: IconInfo },
126
+ success: { icon: IconCheckCircle },
127
+ warning: { icon: IconExclamation },
128
+ danger: { icon: IconCancel }
129
+ };
130
+ var statusClassMap = {
131
+ info: "ph-alert-info",
132
+ success: "ph-alert-success",
133
+ warning: "ph-alert-warning",
134
+ danger: "ph-alert-danger"
135
+ };
136
+ var Alert = forwardRef2(function Alert2(_a, ref) {
137
+ var _b = _a, {
138
+ status = "info",
139
+ title,
140
+ description,
141
+ icon,
142
+ children,
143
+ className,
144
+ onDismiss,
145
+ live,
146
+ dismissLabel = "Dismiss notification",
147
+ role
148
+ } = _b, props = __objRest(_b, [
149
+ "status",
150
+ "title",
151
+ "description",
152
+ "icon",
153
+ "children",
154
+ "className",
155
+ "onDismiss",
156
+ "live",
157
+ "dismissLabel",
158
+ "role"
159
+ ]);
160
+ const config = statusConfig[status];
161
+ const Icon = config.icon;
162
+ return /* @__PURE__ */ jsxs2(
163
+ "div",
164
+ __spreadProps(__spreadValues({
165
+ ref,
166
+ role: role != null ? role : live === "assertive" ? "alert" : live === "polite" ? "status" : void 0,
167
+ "aria-live": live,
168
+ className: cn("ph-alert", statusClassMap[status], className)
169
+ }, props), {
170
+ children: [
171
+ icon != null ? icon : /* @__PURE__ */ jsx2(Icon, { className: "ph-alert-icon mt-0.5 h-5 w-5 shrink-0", "aria-hidden": true }),
172
+ /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
173
+ title && /* @__PURE__ */ jsx2("p", { className: "font-semibold", children: title }),
174
+ description && /* @__PURE__ */ jsx2("p", { className: "mt-1 text-sm text-ph-subtle", children: description }),
175
+ children
176
+ ] }),
177
+ onDismiss && /* @__PURE__ */ jsx2(
178
+ "button",
179
+ {
180
+ type: "button",
181
+ onClick: onDismiss,
182
+ className: "ph-alert-dismiss",
183
+ "aria-label": dismissLabel,
184
+ children: /* @__PURE__ */ jsx2(IconClose, { className: "h-4 w-4", "aria-hidden": true })
185
+ }
186
+ )
187
+ ]
188
+ })
189
+ );
190
+ });
191
+ Alert.displayName = "Alert";
192
+
193
+ // src/components/ui/Badge.tsx
194
+ import { forwardRef as forwardRef3 } from "react";
195
+ import { jsx as jsx3 } from "react/jsx-runtime";
196
+ var variantMap = {
197
+ brand: "ph-badge-brand",
198
+ neutral: "ph-badge-neutral",
199
+ success: "ph-badge-success",
200
+ warning: "ph-badge-warning",
201
+ danger: "ph-badge-danger",
202
+ info: "ph-badge-info",
203
+ outline: "ph-badge-outline"
204
+ };
205
+ var sizeMap = {
206
+ sm: "text-[10px] px-1.5 py-0.5",
207
+ md: ""
208
+ };
209
+ var Badge = forwardRef3(function Badge2(_a, ref) {
210
+ var _b = _a, {
211
+ variant = "neutral",
212
+ size = "md",
213
+ children,
214
+ className
215
+ } = _b, props = __objRest(_b, [
216
+ "variant",
217
+ "size",
218
+ "children",
219
+ "className"
220
+ ]);
221
+ return /* @__PURE__ */ jsx3(
222
+ "span",
223
+ __spreadProps(__spreadValues({
224
+ ref,
225
+ className: cn(
226
+ "ph-badge",
227
+ variantMap[variant],
228
+ sizeMap[size],
229
+ className
230
+ )
231
+ }, props), {
232
+ children
233
+ })
234
+ );
235
+ });
236
+ Badge.displayName = "Badge";
237
+
238
+ // src/components/ui/Card.tsx
239
+ import { forwardRef as forwardRef4 } from "react";
240
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
241
+ var variantMap2 = {
242
+ default: "",
243
+ outlined: "border-2 border-ph-border",
244
+ elevated: "ph-card-elevated",
245
+ highlighted: "ph-card-highlighted"
246
+ };
247
+ var Card = forwardRef4(function Card2(_a, ref) {
248
+ var _b = _a, {
249
+ children,
250
+ title,
251
+ description,
252
+ actions,
253
+ footer,
254
+ media,
255
+ variant = "default",
256
+ className,
257
+ bodyClassName,
258
+ interactive = false,
259
+ titleAs: Title2 = "h3"
260
+ } = _b, props = __objRest(_b, [
261
+ "children",
262
+ "title",
263
+ "description",
264
+ "actions",
265
+ "footer",
266
+ "media",
267
+ "variant",
268
+ "className",
269
+ "bodyClassName",
270
+ "interactive",
271
+ "titleAs"
272
+ ]);
273
+ return /* @__PURE__ */ jsxs3(
274
+ "div",
275
+ __spreadProps(__spreadValues({
276
+ ref,
277
+ className: cn(
278
+ "ph-card",
279
+ variantMap2[variant],
280
+ interactive && "ph-card-interactive",
281
+ className
282
+ )
283
+ }, props), {
284
+ children: [
285
+ media && /* @__PURE__ */ jsx4("div", { className: "ph-card-media", children: media }),
286
+ /* @__PURE__ */ jsxs3("div", { className: cn("ph-card-body", bodyClassName), children: [
287
+ title && /* @__PURE__ */ jsx4(Title2, { className: "ph-card-title", children: title }),
288
+ description && /* @__PURE__ */ jsx4("p", { className: "text-sm text-ph-subtle", children: description }),
289
+ children,
290
+ actions && /* @__PURE__ */ jsx4("div", { className: "ph-card-actions", children: actions })
291
+ ] }),
292
+ footer && /* @__PURE__ */ jsx4("div", { className: "border-t border-ph-border px-6 py-4 text-xs text-ph-subtle", children: footer })
293
+ ]
294
+ })
295
+ );
296
+ });
297
+ Card.displayName = "Card";
298
+
299
+ // src/components/ui/Drawer.tsx
300
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
301
+ var sideMap = {
302
+ left: "left-0 border-r",
303
+ right: "right-0 border-l"
304
+ };
305
+ var sizeMap2 = {
306
+ sm: "w-[min(100%,18rem)]",
307
+ md: "w-[min(100%,22rem)]",
308
+ lg: "w-[min(100%,30rem)]"
309
+ };
310
+ function Drawer({
311
+ open = false,
312
+ onClose,
313
+ title,
314
+ children,
315
+ footer,
316
+ side = "right",
317
+ size = "md",
318
+ className,
319
+ showCloseButton = true
320
+ }) {
321
+ if (!open) return null;
322
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
323
+ /* @__PURE__ */ jsx5("div", { className: "fixed inset-0 z-[120] bg-black/45 backdrop-blur-[2px]", role: "presentation", onClick: onClose }),
324
+ /* @__PURE__ */ jsxs4(
325
+ "aside",
326
+ {
327
+ className: cn(
328
+ "fixed inset-y-0 z-[130] flex flex-col overflow-y-auto border-ph-border bg-ph-surface shadow-ph-md",
329
+ sideMap[side],
330
+ sizeMap2[size],
331
+ className
332
+ ),
333
+ children: [
334
+ (title || showCloseButton) && /* @__PURE__ */ jsxs4("header", { className: "flex items-center justify-between border-b border-ph-border px-4 py-3", children: [
335
+ /* @__PURE__ */ jsx5("span", { className: "text-sm font-bold text-ph-ink", children: title }),
336
+ showCloseButton && onClose && /* @__PURE__ */ jsx5(Button, { variant: "ghost", className: "ph-btn-circle", onClick: onClose, "aria-label": "Close drawer", children: /* @__PURE__ */ jsx5(IconClose, { className: "h-5 w-5" }) })
337
+ ] }),
338
+ /* @__PURE__ */ jsx5("div", { className: "flex-1", children }),
339
+ footer && /* @__PURE__ */ jsx5("footer", { className: "border-t border-ph-border px-4 py-3", children: footer })
340
+ ]
341
+ }
342
+ )
343
+ ] });
344
+ }
345
+
346
+ // src/components/ui/Kbd.tsx
347
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
348
+ var platformLabels = {
349
+ text: {
350
+ command: "Command",
351
+ cmd: "Command",
352
+ option: "Option",
353
+ alt: "Alt",
354
+ control: "Control",
355
+ ctrl: "Control",
356
+ shift: "Shift"
357
+ },
358
+ mac: {
359
+ command: "\u2318",
360
+ cmd: "\u2318",
361
+ option: "\u2325",
362
+ alt: "\u2325",
363
+ control: "\u2303",
364
+ ctrl: "\u2303",
365
+ shift: "\u21E7"
366
+ },
367
+ windows: {
368
+ command: "Win",
369
+ cmd: "Win",
370
+ option: "Alt",
371
+ alt: "Alt",
372
+ control: "Ctrl",
373
+ ctrl: "Ctrl",
374
+ shift: "Shift"
375
+ }
376
+ };
377
+ var spokenLabels = {
378
+ "\u2318": "Command",
379
+ "\u2325": "Option",
380
+ "\u2303": "Control",
381
+ "\u21E7": "Shift",
382
+ "\u21B5": "Enter",
383
+ "\u23CE": "Enter",
384
+ "\u232B": "Backspace",
385
+ "\u238B": "Escape"
386
+ };
387
+ function Kbd(_a) {
388
+ var _b = _a, {
389
+ variant = "shortcut",
390
+ keys,
391
+ platform = "text",
392
+ separator,
393
+ children,
394
+ className,
395
+ "aria-label": ariaLabel
396
+ } = _b, props = __objRest(_b, [
397
+ "variant",
398
+ "keys",
399
+ "platform",
400
+ "separator",
401
+ "children",
402
+ "className",
403
+ "aria-label"
404
+ ]);
405
+ if (variant === "token") {
406
+ return /* @__PURE__ */ jsx6("code", __spreadProps(__spreadValues({ className: cn("ph-code-token ph-kbd", className), "aria-label": ariaLabel }, props), { children }));
407
+ }
408
+ const sourceKeys = (keys == null ? void 0 : keys.length) ? keys : children != null ? [children] : [];
409
+ const displayKeys = sourceKeys.map((key) => formatKey(key, platform));
410
+ const accessibleLabel = ariaLabel != null ? ariaLabel : getShortcutLabel(displayKeys);
411
+ if (variant === "key") {
412
+ return /* @__PURE__ */ jsx6("kbd", __spreadProps(__spreadValues({ className: cn("ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys[0] }));
413
+ }
414
+ return /* @__PURE__ */ jsx6("kbd", __spreadProps(__spreadValues({ className: cn("ph-shortcut-group ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys.map((key, index) => /* @__PURE__ */ jsxs5("span", { className: "contents", children: [
415
+ index > 0 && separator != null ? /* @__PURE__ */ jsx6("span", { className: "ph-shortcut-separator", "aria-hidden": "true", children: separator }) : null,
416
+ /* @__PURE__ */ jsx6("span", { className: "ph-shortcut-key", "aria-hidden": accessibleLabel ? true : void 0, children: key })
417
+ ] }, index)) }));
418
+ }
419
+ function formatKey(key, platform) {
420
+ var _a;
421
+ if (typeof key !== "string") return key;
422
+ return (_a = platformLabels[platform][key.toLowerCase()]) != null ? _a : key;
423
+ }
424
+ function getShortcutLabel(keys) {
425
+ const labels = keys.map((key) => {
426
+ var _a;
427
+ if (typeof key !== "string" && typeof key !== "number") return null;
428
+ const value = String(key);
429
+ return (_a = spokenLabels[value]) != null ? _a : value;
430
+ });
431
+ return labels.every((label) => label != null) ? labels.join(" + ") : void 0;
432
+ }
433
+
434
+ // src/components/ui/Loader.tsx
435
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
436
+ var loaderSizeClass = {
437
+ sm: "ph-loader-sm",
438
+ md: "ph-loader-md",
439
+ lg: "ph-loader-lg"
440
+ };
441
+ var skeletonShapeClass = {
442
+ title: "ph-skeleton-title",
443
+ text: "ph-skeleton-text",
444
+ "short-text": "ph-skeleton-text-short",
445
+ avatar: "ph-skeleton-avatar",
446
+ button: "ph-skeleton-button",
447
+ block: "ph-skeleton-block"
448
+ };
449
+ function Loader(_a) {
450
+ var _b = _a, {
451
+ variant = "spinner",
452
+ size = "md",
453
+ label = "Loading",
454
+ className
455
+ } = _b, props = __objRest(_b, [
456
+ "variant",
457
+ "size",
458
+ "label",
459
+ "className"
460
+ ]);
461
+ return /* @__PURE__ */ jsxs6(
462
+ "span",
463
+ __spreadProps(__spreadValues({
464
+ role: "status",
465
+ "aria-label": label,
466
+ className: cn("ph-loader", loaderSizeClass[size], className)
467
+ }, props), {
468
+ children: [
469
+ variant === "spinner" ? /* @__PURE__ */ jsx7("span", { className: "ph-loading", "aria-hidden": true }) : null,
470
+ variant === "dots" ? /* @__PURE__ */ jsxs6("span", { className: "ph-loading-dots", "aria-hidden": true, children: [
471
+ /* @__PURE__ */ jsx7("span", {}),
472
+ /* @__PURE__ */ jsx7("span", {}),
473
+ /* @__PURE__ */ jsx7("span", {})
474
+ ] }) : null,
475
+ variant === "pulse" ? /* @__PURE__ */ jsx7("span", { className: "ph-loading-pulse", "aria-hidden": true }) : null
476
+ ]
477
+ })
478
+ );
479
+ }
480
+ function Skeleton(_a) {
481
+ var _b = _a, { shape = "text", className } = _b, props = __objRest(_b, ["shape", "className"]);
482
+ return /* @__PURE__ */ jsx7(
483
+ "span",
484
+ __spreadValues({
485
+ className: cn("ph-skeleton", skeletonShapeClass[shape], className),
486
+ "aria-hidden": "true"
487
+ }, props)
488
+ );
489
+ }
490
+ function LoadingState(_a) {
491
+ var _b = _a, {
492
+ label = "Loading",
493
+ title = "Loading",
494
+ description,
495
+ variant = "spinner",
496
+ size = "lg",
497
+ className
498
+ } = _b, props = __objRest(_b, [
499
+ "label",
500
+ "title",
501
+ "description",
502
+ "variant",
503
+ "size",
504
+ "className"
505
+ ]);
506
+ return /* @__PURE__ */ jsxs6("div", __spreadProps(__spreadValues({ className: cn("ph-loading-state", className), role: "status", "aria-label": label }, props), { children: [
507
+ /* @__PURE__ */ jsx7(Loader, { variant, size, label, "aria-hidden": "true" }),
508
+ /* @__PURE__ */ jsxs6("div", { className: "ph-loading-state__copy", children: [
509
+ /* @__PURE__ */ jsx7("strong", { children: title }),
510
+ description ? /* @__PURE__ */ jsx7("span", { children: description }) : null
511
+ ] })
512
+ ] }));
513
+ }
514
+
515
+ // src/components/ui/AuthLayout.tsx
516
+ import { useId } from "react";
517
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
518
+ function AuthLayout(_a) {
519
+ var _b = _a, { brand, footer, aside, children, className } = _b, props = __objRest(_b, ["brand", "footer", "aside", "children", "className"]);
520
+ return /* @__PURE__ */ jsxs7("div", __spreadProps(__spreadValues({ className: cn("ph-auth-layout", aside != null && "ph-auth-layout--split", className) }, props), { children: [
521
+ aside ? /* @__PURE__ */ jsx8("aside", { className: "ph-auth-layout__aside", children: aside }) : null,
522
+ /* @__PURE__ */ jsx8("div", { className: "ph-auth-layout__main", children: /* @__PURE__ */ jsxs7("div", { className: "ph-auth-layout__column", children: [
523
+ brand ? /* @__PURE__ */ jsx8("div", { className: "ph-auth-layout__brand", children: brand }) : null,
524
+ children,
525
+ footer ? /* @__PURE__ */ jsx8("footer", { className: "ph-auth-layout__footer", children: footer }) : null
526
+ ] }) })
527
+ ] }));
528
+ }
529
+ function AuthCard(_a) {
530
+ var _b = _a, { title, description, footer, children, className } = _b, props = __objRest(_b, ["title", "description", "footer", "children", "className"]);
531
+ const titleId = useId();
532
+ return /* @__PURE__ */ jsxs7("section", __spreadProps(__spreadValues({ className: cn("ph-auth-card", className), "aria-labelledby": titleId }, props), { children: [
533
+ /* @__PURE__ */ jsxs7("header", { className: "ph-auth-card__header", children: [
534
+ /* @__PURE__ */ jsx8("h1", { id: titleId, children: title }),
535
+ description ? /* @__PURE__ */ jsx8("p", { children: description }) : null
536
+ ] }),
537
+ /* @__PURE__ */ jsx8("div", { className: "ph-auth-card__body", children }),
538
+ footer ? /* @__PURE__ */ jsx8("footer", { className: "ph-auth-card__footer", children: footer }) : null
539
+ ] }));
540
+ }
541
+ function AuthDivider(_a) {
542
+ var _b = _a, { children = "or continue with", className } = _b, props = __objRest(_b, ["children", "className"]);
543
+ return /* @__PURE__ */ jsx8("div", __spreadProps(__spreadValues({ className: cn("ph-auth-divider", className) }, props), { children: /* @__PURE__ */ jsx8("span", { children }) }));
544
+ }
545
+
546
+ // src/components/ui/SettingsLayout.tsx
547
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
548
+ function SettingsNav(_a) {
549
+ var _b = _a, { groups, className } = _b, props = __objRest(_b, ["groups", "className"]);
550
+ return /* @__PURE__ */ jsx9("div", __spreadProps(__spreadValues({ className: cn("ph-settings-nav", className) }, props), { children: groups.map((group, index) => /* @__PURE__ */ jsxs8("div", { className: "ph-settings-nav__group", children: [
551
+ /* @__PURE__ */ jsx9("h3", { children: group.label }),
552
+ /* @__PURE__ */ jsx9("div", { className: "ph-settings-nav__items", children: group.items.map((item) => /* @__PURE__ */ jsxs8(
553
+ "a",
554
+ {
555
+ href: item.href,
556
+ className: cn("ph-settings-nav__item", item.active && "ph-settings-nav__item--active"),
557
+ "aria-current": item.active ? "page" : void 0,
558
+ children: [
559
+ item.icon ? /* @__PURE__ */ jsx9("span", { className: "ph-settings-nav__icon", children: item.icon }) : null,
560
+ /* @__PURE__ */ jsx9("span", { children: item.label }),
561
+ item.badge ? /* @__PURE__ */ jsx9("span", { className: "ph-settings-nav__badge", children: item.badge }) : null
562
+ ]
563
+ },
564
+ item.id
565
+ )) })
566
+ ] }, index)) }));
567
+ }
568
+ function SettingsLayout(_a) {
569
+ var _b = _a, {
570
+ title,
571
+ description,
572
+ actions,
573
+ navigation,
574
+ navigationLabel = "Settings",
575
+ children,
576
+ className
577
+ } = _b, props = __objRest(_b, [
578
+ "title",
579
+ "description",
580
+ "actions",
581
+ "navigation",
582
+ "navigationLabel",
583
+ "children",
584
+ "className"
585
+ ]);
586
+ return /* @__PURE__ */ jsxs8("section", __spreadProps(__spreadValues({ className: cn("ph-settings-layout", className) }, props), { children: [
587
+ /* @__PURE__ */ jsxs8("header", { className: "ph-settings-layout__header", children: [
588
+ /* @__PURE__ */ jsxs8("div", { children: [
589
+ /* @__PURE__ */ jsx9("h2", { children: title }),
590
+ description ? /* @__PURE__ */ jsx9("p", { children: description }) : null
591
+ ] }),
592
+ actions ? /* @__PURE__ */ jsx9("div", { className: "ph-settings-layout__actions", children: actions }) : null
593
+ ] }),
594
+ /* @__PURE__ */ jsxs8("details", { className: "ph-settings-layout__mobile-nav", children: [
595
+ /* @__PURE__ */ jsxs8("summary", { children: [
596
+ /* @__PURE__ */ jsx9(IconTuning, { className: "h-4 w-4", "aria-hidden": true }),
597
+ "Settings menu"
598
+ ] }),
599
+ /* @__PURE__ */ jsx9("nav", { "aria-label": navigationLabel, children: navigation })
600
+ ] }),
601
+ /* @__PURE__ */ jsxs8("div", { className: "ph-settings-layout__grid", children: [
602
+ /* @__PURE__ */ jsx9("aside", { className: "ph-settings-layout__sidebar", children: /* @__PURE__ */ jsx9("nav", { "aria-label": navigationLabel, children: navigation }) }),
603
+ /* @__PURE__ */ jsx9("div", { className: "ph-settings-layout__content", children })
604
+ ] })
605
+ ] }));
606
+ }
607
+
608
+ // src/components/ui/Input.tsx
609
+ import { forwardRef as forwardRef5, useId as useId3 } from "react";
610
+
611
+ // src/components/ui/FormField.tsx
612
+ import { useId as useId2 } from "react";
613
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
614
+ function FormField(_a) {
615
+ var _b = _a, {
616
+ controlId,
617
+ label,
618
+ hideLabel = false,
619
+ helperText,
620
+ error,
621
+ required = false,
622
+ disabled = false,
623
+ children,
624
+ className
625
+ } = _b, props = __objRest(_b, [
626
+ "controlId",
627
+ "label",
628
+ "hideLabel",
629
+ "helperText",
630
+ "error",
631
+ "required",
632
+ "disabled",
633
+ "children",
634
+ "className"
635
+ ]);
636
+ const generatedId = useId2();
637
+ const id = controlId != null ? controlId : generatedId;
638
+ const descriptionId = helperText && !error ? `${id}-description` : void 0;
639
+ const errorId = error ? `${id}-error` : void 0;
640
+ const controlProps = {
641
+ id,
642
+ "aria-describedby": descriptionId,
643
+ "aria-errormessage": errorId,
644
+ "aria-invalid": error ? true : void 0
645
+ };
646
+ return /* @__PURE__ */ jsxs9("div", __spreadProps(__spreadValues({ className: cn("ph-field", className) }, props), { children: [
647
+ label ? /* @__PURE__ */ jsxs9(
648
+ "label",
649
+ {
650
+ htmlFor: id,
651
+ className: cn("ph-label", hideLabel && "sr-only", disabled && "opacity-50"),
652
+ children: [
653
+ label,
654
+ required ? /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: " *" }) : null
655
+ ]
656
+ }
657
+ ) : null,
658
+ typeof children === "function" ? children(controlProps) : children,
659
+ descriptionId ? /* @__PURE__ */ jsx10("p", { id: descriptionId, className: "mt-1 text-xs text-ph-subtle", children: helperText }) : null,
660
+ errorId ? /* @__PURE__ */ jsx10("p", { id: errorId, className: "mt-1 text-xs font-medium text-ph-danger", children: error }) : null
661
+ ] }));
662
+ }
663
+
664
+ // src/components/ui/Input.tsx
665
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
666
+ var sizeMap3 = {
667
+ sm: "ph-input-sm",
668
+ md: "",
669
+ lg: "ph-input-lg"
670
+ };
671
+ function joinIds(...ids) {
672
+ const value = ids.filter(Boolean).join(" ");
673
+ return value || void 0;
674
+ }
675
+ var Input = forwardRef5(function Input2(_a, ref) {
676
+ var _b = _a, {
677
+ id: idProp,
678
+ label,
679
+ hideLabel = false,
680
+ error,
681
+ helperText,
682
+ size = "md",
683
+ variant = "default",
684
+ className,
685
+ wrapperClassName,
686
+ disabled,
687
+ required,
688
+ "aria-describedby": ariaDescribedBy
689
+ } = _b, props = __objRest(_b, [
690
+ "id",
691
+ "label",
692
+ "hideLabel",
693
+ "error",
694
+ "helperText",
695
+ "size",
696
+ "variant",
697
+ "className",
698
+ "wrapperClassName",
699
+ "disabled",
700
+ "required",
701
+ "aria-describedby"
702
+ ]);
703
+ const autoId = useId3();
704
+ const id = idProp != null ? idProp : autoId;
705
+ const hasError = Boolean(error);
706
+ return /* @__PURE__ */ jsx11(
707
+ FormField,
708
+ {
709
+ controlId: id,
710
+ label,
711
+ hideLabel,
712
+ helperText,
713
+ error,
714
+ required,
715
+ disabled,
716
+ className: wrapperClassName,
717
+ children: (fieldProps) => /* @__PURE__ */ jsx11(
718
+ "input",
719
+ __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
720
+ ref,
721
+ disabled,
722
+ required,
723
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
724
+ className: cn(
725
+ "ph-input w-full",
726
+ sizeMap3[size],
727
+ variant === "ghost" && "ph-input-ghost",
728
+ hasError && "ph-input-error",
729
+ disabled && "cursor-not-allowed opacity-60",
730
+ className
731
+ )
732
+ }), props)
733
+ )
734
+ }
735
+ );
736
+ });
737
+ Input.displayName = "Input";
738
+ var Select = forwardRef5(function Select2(_a, ref) {
739
+ var _b = _a, {
740
+ id: idProp,
741
+ label,
742
+ hideLabel = false,
743
+ error,
744
+ helperText,
745
+ size = "md",
746
+ className,
747
+ wrapperClassName,
748
+ disabled,
749
+ children,
750
+ required,
751
+ "aria-describedby": ariaDescribedBy
752
+ } = _b, props = __objRest(_b, [
753
+ "id",
754
+ "label",
755
+ "hideLabel",
756
+ "error",
757
+ "helperText",
758
+ "size",
759
+ "className",
760
+ "wrapperClassName",
761
+ "disabled",
762
+ "children",
763
+ "required",
764
+ "aria-describedby"
765
+ ]);
766
+ const autoId = useId3();
767
+ const id = idProp != null ? idProp : autoId;
768
+ const hasError = Boolean(error);
769
+ return /* @__PURE__ */ jsx11(FormField, { controlId: id, label, hideLabel, helperText, error, required, disabled, className: wrapperClassName, children: (fieldProps) => /* @__PURE__ */ jsx11(
770
+ "select",
771
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
772
+ ref,
773
+ disabled,
774
+ required,
775
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
776
+ className: cn(
777
+ "ph-select w-full",
778
+ sizeMap3[size],
779
+ hasError && "ph-input-error",
780
+ disabled && "cursor-not-allowed opacity-60",
781
+ className
782
+ )
783
+ }), props), {
784
+ children
785
+ })
786
+ ) });
787
+ });
788
+ Select.displayName = "Select";
789
+ var Textarea = forwardRef5(function Textarea2(_a, ref) {
790
+ var _b = _a, {
791
+ id: idProp,
792
+ label,
793
+ hideLabel = false,
794
+ error,
795
+ helperText,
796
+ size = "md",
797
+ className,
798
+ wrapperClassName,
799
+ disabled,
800
+ required,
801
+ "aria-describedby": ariaDescribedBy
802
+ } = _b, props = __objRest(_b, [
803
+ "id",
804
+ "label",
805
+ "hideLabel",
806
+ "error",
807
+ "helperText",
808
+ "size",
809
+ "className",
810
+ "wrapperClassName",
811
+ "disabled",
812
+ "required",
813
+ "aria-describedby"
814
+ ]);
815
+ const autoId = useId3();
816
+ const id = idProp != null ? idProp : autoId;
817
+ const hasError = Boolean(error);
818
+ return /* @__PURE__ */ jsx11(FormField, { controlId: id, label, hideLabel, helperText, error, required, disabled, className: wrapperClassName, children: (fieldProps) => /* @__PURE__ */ jsx11(
819
+ "textarea",
820
+ __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
821
+ ref,
822
+ disabled,
823
+ required,
824
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
825
+ className: cn(
826
+ "ph-textarea w-full",
827
+ sizeMap3[size],
828
+ hasError && "ph-input-error",
829
+ disabled && "cursor-not-allowed opacity-60",
830
+ className
831
+ )
832
+ }), props)
833
+ ) });
834
+ });
835
+ Textarea.displayName = "Textarea";
836
+ var Checkbox = forwardRef5(function Checkbox2(_a, ref) {
837
+ var _b = _a, {
838
+ id: idProp,
839
+ label,
840
+ error,
841
+ helperText,
842
+ className,
843
+ wrapperClassName,
844
+ disabled,
845
+ "aria-describedby": ariaDescribedBy
846
+ } = _b, props = __objRest(_b, [
847
+ "id",
848
+ "label",
849
+ "error",
850
+ "helperText",
851
+ "className",
852
+ "wrapperClassName",
853
+ "disabled",
854
+ "aria-describedby"
855
+ ]);
856
+ const autoId = useId3();
857
+ const id = idProp != null ? idProp : autoId;
858
+ const hasError = Boolean(error);
859
+ const descriptionId = helperText && !hasError ? `${id}-description` : void 0;
860
+ const errorId = error ? `${id}-error` : void 0;
861
+ return /* @__PURE__ */ jsxs10("div", { className: cn("ph-control-row", wrapperClassName), children: [
862
+ /* @__PURE__ */ jsxs10("span", { className: "ph-checkbox-wrap", children: [
863
+ /* @__PURE__ */ jsx11(
864
+ "input",
865
+ __spreadValues({
866
+ ref,
867
+ id,
868
+ type: "checkbox",
869
+ disabled,
870
+ "aria-invalid": hasError || void 0,
871
+ "aria-describedby": joinIds(ariaDescribedBy, descriptionId),
872
+ "aria-errormessage": errorId,
873
+ className: cn(
874
+ "ph-checkbox",
875
+ hasError && "border-ph-danger",
876
+ disabled && "cursor-not-allowed opacity-60",
877
+ className
878
+ )
879
+ }, props)
880
+ ),
881
+ /* @__PURE__ */ jsx11(IconCheck, { className: "ph-checkbox-icon", "aria-hidden": true })
882
+ ] }),
883
+ /* @__PURE__ */ jsxs10("div", { className: "ph-control-copy", children: [
884
+ /* @__PURE__ */ jsx11("label", { htmlFor: id, className: cn("cursor-pointer", disabled && "opacity-60"), children: label }),
885
+ descriptionId ? /* @__PURE__ */ jsx11("p", { id: descriptionId, className: "text-xs text-ph-subtle", children: helperText }) : null,
886
+ errorId ? /* @__PURE__ */ jsx11("p", { id: errorId, className: "text-xs font-medium text-ph-danger", children: error }) : null
887
+ ] })
888
+ ] });
889
+ });
890
+ Checkbox.displayName = "Checkbox";
891
+ var Radio = forwardRef5(function Radio2(_a, ref) {
892
+ var _b = _a, {
893
+ id: idProp,
894
+ label,
895
+ className,
896
+ wrapperClassName,
897
+ disabled
898
+ } = _b, props = __objRest(_b, [
899
+ "id",
900
+ "label",
901
+ "className",
902
+ "wrapperClassName",
903
+ "disabled"
904
+ ]);
905
+ const autoId = useId3();
906
+ const id = idProp != null ? idProp : autoId;
907
+ return /* @__PURE__ */ jsxs10("div", { className: cn("ph-control-row", wrapperClassName, disabled && "opacity-60"), children: [
908
+ /* @__PURE__ */ jsx11(
909
+ "input",
910
+ __spreadValues({
911
+ ref,
912
+ id,
913
+ type: "radio",
914
+ disabled,
915
+ className: cn("ph-radio", disabled && "cursor-not-allowed", className)
916
+ }, props)
917
+ ),
918
+ /* @__PURE__ */ jsx11("label", { htmlFor: id, className: cn("cursor-pointer", disabled && "opacity-60"), children: label })
919
+ ] });
920
+ });
921
+ Radio.displayName = "Radio";
922
+ var Toggle = forwardRef5(function Toggle2(_a, ref) {
923
+ var _b = _a, {
924
+ id: idProp,
925
+ label,
926
+ className,
927
+ wrapperClassName,
928
+ disabled
929
+ } = _b, props = __objRest(_b, [
930
+ "id",
931
+ "label",
932
+ "className",
933
+ "wrapperClassName",
934
+ "disabled"
935
+ ]);
936
+ const autoId = useId3();
937
+ const id = idProp != null ? idProp : autoId;
938
+ return /* @__PURE__ */ jsxs10("label", { className: cn("ph-control-row-between", wrapperClassName, disabled && "opacity-60"), children: [
939
+ /* @__PURE__ */ jsx11("span", { className: disabled ? "opacity-60" : void 0, children: label }),
940
+ /* @__PURE__ */ jsx11(
941
+ "input",
942
+ __spreadValues({
943
+ ref,
944
+ id,
945
+ type: "checkbox",
946
+ role: "switch",
947
+ disabled,
948
+ className: cn("ph-toggle", disabled && "cursor-not-allowed", className)
949
+ }, props)
950
+ )
951
+ ] });
952
+ });
953
+ Toggle.displayName = "Toggle";
954
+ var Range = forwardRef5(function Range2(_a, ref) {
955
+ var _b = _a, {
956
+ id: idProp,
957
+ label,
958
+ minLabel,
959
+ maxLabel,
960
+ valueLabel,
961
+ wrapperClassName,
962
+ className
963
+ } = _b, props = __objRest(_b, [
964
+ "id",
965
+ "label",
966
+ "minLabel",
967
+ "maxLabel",
968
+ "valueLabel",
969
+ "wrapperClassName",
970
+ "className"
971
+ ]);
972
+ const autoId = useId3();
973
+ const id = idProp != null ? idProp : autoId;
974
+ return /* @__PURE__ */ jsxs10("div", { className: cn("ph-field", wrapperClassName), children: [
975
+ label && /* @__PURE__ */ jsx11("label", { htmlFor: id, className: "ph-label", children: label }),
976
+ /* @__PURE__ */ jsx11("input", __spreadValues({ ref, id, type: "range", className: cn("ph-range", className) }, props)),
977
+ (minLabel || valueLabel || maxLabel) && /* @__PURE__ */ jsxs10("div", { className: "flex justify-between text-xs text-ph-mutedtext", children: [
978
+ /* @__PURE__ */ jsx11("span", { children: minLabel }),
979
+ /* @__PURE__ */ jsx11("span", { children: valueLabel }),
980
+ /* @__PURE__ */ jsx11("span", { children: maxLabel })
981
+ ] })
982
+ ] });
983
+ });
984
+ Range.displayName = "Range";
985
+ var FileUpload = forwardRef5(function FileUpload2(_a, ref) {
986
+ var _b = _a, {
987
+ id: idProp,
988
+ label,
989
+ prompt = "Drop file or browse",
990
+ wrapperClassName,
991
+ className
992
+ } = _b, props = __objRest(_b, [
993
+ "id",
994
+ "label",
995
+ "prompt",
996
+ "wrapperClassName",
997
+ "className"
998
+ ]);
999
+ const autoId = useId3();
1000
+ const id = idProp != null ? idProp : autoId;
1001
+ return /* @__PURE__ */ jsxs10("div", { className: cn("ph-field", wrapperClassName), children: [
1002
+ label && /* @__PURE__ */ jsx11("label", { htmlFor: id, className: "ph-label", children: label }),
1003
+ /* @__PURE__ */ jsxs10("label", { htmlFor: id, className: "ph-file-upload", children: [
1004
+ /* @__PURE__ */ jsx11("input", __spreadValues({ ref, id, type: "file", className: cn("sr-only", className) }, props)),
1005
+ prompt
1006
+ ] })
1007
+ ] });
1008
+ });
1009
+ FileUpload.displayName = "FileUpload";
1010
+
1011
+ // src/components/ui/Modal.tsx
1012
+ import * as Dialog from "@radix-ui/react-dialog";
1013
+ import { useRef } from "react";
1014
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1015
+ var sizeMap4 = {
1016
+ sm: "max-w-sm",
1017
+ md: "max-w-lg",
1018
+ lg: "max-w-2xl",
1019
+ xl: "max-w-4xl",
1020
+ full: "max-w-none"
1021
+ };
1022
+ function Modal({
1023
+ open = false,
1024
+ onClose,
1025
+ title,
1026
+ description,
1027
+ children,
1028
+ footer,
1029
+ size = "md",
1030
+ className,
1031
+ showCloseButton = true,
1032
+ closeOnOutsideClick = true,
1033
+ closeOnEscape = true,
1034
+ "aria-label": ariaLabel
1035
+ }) {
1036
+ const canDismiss = Boolean(onClose);
1037
+ const restoreFocusRef = useRef(null);
1038
+ return /* @__PURE__ */ jsx12(
1039
+ Dialog.Root,
1040
+ {
1041
+ open,
1042
+ onOpenChange: (nextOpen) => {
1043
+ if (!nextOpen) onClose == null ? void 0 : onClose();
1044
+ },
1045
+ children: /* @__PURE__ */ jsxs11(Dialog.Portal, { children: [
1046
+ /* @__PURE__ */ jsx12(Dialog.Overlay, { className: "ph-modal-overlay" }),
1047
+ /* @__PURE__ */ jsxs11(
1048
+ Dialog.Content,
1049
+ __spreadProps(__spreadValues({
1050
+ className: cn("ph-modal-panel", sizeMap4[size], className),
1051
+ "aria-label": ariaLabel
1052
+ }, description ? {} : { "aria-describedby": void 0 }), {
1053
+ onOpenAutoFocus: () => {
1054
+ restoreFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1055
+ },
1056
+ onCloseAutoFocus: (event) => {
1057
+ var _a;
1058
+ event.preventDefault();
1059
+ (_a = restoreFocusRef.current) == null ? void 0 : _a.focus();
1060
+ },
1061
+ onEscapeKeyDown: (event) => {
1062
+ if (!canDismiss || !closeOnEscape) event.preventDefault();
1063
+ },
1064
+ onPointerDownOutside: (event) => {
1065
+ if (!canDismiss || !closeOnOutsideClick) event.preventDefault();
1066
+ },
1067
+ children: [
1068
+ title ? null : /* @__PURE__ */ jsx12(Dialog.Title, { className: "sr-only", children: ariaLabel != null ? ariaLabel : "Dialog" }),
1069
+ title || description || showCloseButton && canDismiss ? /* @__PURE__ */ jsxs11("header", { className: "ph-modal-header", children: [
1070
+ /* @__PURE__ */ jsxs11("div", { className: "min-w-0", children: [
1071
+ title ? /* @__PURE__ */ jsx12(Dialog.Title, { className: "text-lg font-bold text-ph-ink", children: title }) : null,
1072
+ description ? /* @__PURE__ */ jsx12(Dialog.Description, { className: "mt-1 text-sm text-ph-subtle", children: description }) : null
1073
+ ] }),
1074
+ showCloseButton && canDismiss ? /* @__PURE__ */ jsx12(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx12("button", { type: "button", className: "ph-modal-close", "aria-label": "Close dialog", children: /* @__PURE__ */ jsx12(IconClose, { className: "h-5 w-5", "aria-hidden": true }) }) }) : null
1075
+ ] }) : null,
1076
+ /* @__PURE__ */ jsx12("div", { className: "ph-modal-body", children }),
1077
+ footer ? /* @__PURE__ */ jsx12("div", { className: "ph-modal-footer", children: footer }) : null
1078
+ ]
1079
+ })
1080
+ )
1081
+ ] })
1082
+ }
1083
+ );
1084
+ }
1085
+
1086
+ // src/components/ui/Navigation.tsx
1087
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1088
+ function Breadcrumbs({ items, label = "Breadcrumb", className }) {
1089
+ return /* @__PURE__ */ jsx13("nav", { "aria-label": label, className: cn("ph-breadcrumbs", className), children: items.map((item, index) => /* @__PURE__ */ jsxs12("span", { className: "contents", children: [
1090
+ index > 0 ? /* @__PURE__ */ jsx13("span", { className: "ph-breadcrumb-sep", "aria-hidden": "true", children: "/" }) : null,
1091
+ item.current || !item.href ? /* @__PURE__ */ jsx13("span", { className: "ph-breadcrumb-current", "aria-current": item.current ? "page" : void 0, children: item.label }) : /* @__PURE__ */ jsx13("a", { href: item.href, className: "ph-breadcrumb-link", children: item.label })
1092
+ ] }, `${item.label}-${index}`)) });
1093
+ }
1094
+ function Pagination({
1095
+ page,
1096
+ totalPages,
1097
+ onPageChange,
1098
+ label = "Pagination",
1099
+ compact = false,
1100
+ className
1101
+ }) {
1102
+ const pages = compact ? [Math.max(1, page - 1), page, Math.min(totalPages, page + 1)] : [1, 2, 3, totalPages];
1103
+ const uniquePages = Array.from(new Set(pages)).filter((n) => n >= 1 && n <= totalPages);
1104
+ return /* @__PURE__ */ jsxs12("nav", { "aria-label": label, className: cn("ph-pagination", className), children: [
1105
+ /* @__PURE__ */ jsx13(
1106
+ "button",
1107
+ {
1108
+ type: "button",
1109
+ className: "ph-pagination-btn",
1110
+ disabled: page <= 1,
1111
+ "aria-label": "Previous page",
1112
+ onClick: () => onPageChange == null ? void 0 : onPageChange(page - 1),
1113
+ children: /* @__PURE__ */ jsx13(IconChevronLeft, { className: "mx-auto h-4 w-4", "aria-hidden": true })
1114
+ }
1115
+ ),
1116
+ uniquePages.map((pageNumber, index) => /* @__PURE__ */ jsxs12("span", { className: "contents", children: [
1117
+ !compact && index === uniquePages.length - 1 && pageNumber > 4 ? /* @__PURE__ */ jsx13("span", { className: "ph-pagination-ellipsis", "aria-hidden": "true", children: "..." }) : null,
1118
+ /* @__PURE__ */ jsx13(
1119
+ "button",
1120
+ {
1121
+ type: "button",
1122
+ className: cn("ph-pagination-btn", pageNumber === page && "ph-pagination-btn-active"),
1123
+ "aria-current": pageNumber === page ? "page" : void 0,
1124
+ onClick: () => onPageChange == null ? void 0 : onPageChange(pageNumber),
1125
+ children: pageNumber
1126
+ }
1127
+ )
1128
+ ] }, pageNumber)),
1129
+ /* @__PURE__ */ jsx13(
1130
+ "button",
1131
+ {
1132
+ type: "button",
1133
+ className: "ph-pagination-btn",
1134
+ disabled: page >= totalPages,
1135
+ "aria-label": "Next page",
1136
+ onClick: () => onPageChange == null ? void 0 : onPageChange(page + 1),
1137
+ children: /* @__PURE__ */ jsx13(IconChevronRight, { className: "mx-auto h-4 w-4", "aria-hidden": true })
1138
+ }
1139
+ )
1140
+ ] });
1141
+ }
1142
+
1143
+ // src/components/ui/Panel.tsx
1144
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1145
+ function Panel(_a) {
1146
+ var _b = _a, { title, description, children, className } = _b, props = __objRest(_b, ["title", "description", "children", "className"]);
1147
+ return /* @__PURE__ */ jsxs13("div", __spreadProps(__spreadValues({ className: cn("ph-panel", className) }, props), { children: [
1148
+ title && /* @__PURE__ */ jsx14("h3", { className: "text-sm font-semibold uppercase tracking-wider text-ph-mutedtext", children: title }),
1149
+ description && /* @__PURE__ */ jsx14("p", { className: "text-sm text-ph-subtle", children: description }),
1150
+ children
1151
+ ] }));
1152
+ }
1153
+
1154
+ // src/components/ui/Rating.tsx
1155
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1156
+ function Rating(_a) {
1157
+ var _b = _a, {
1158
+ label,
1159
+ value = 0,
1160
+ max = 5,
1161
+ readOnly = true,
1162
+ onChange,
1163
+ className,
1164
+ wrapperClassName
1165
+ } = _b, props = __objRest(_b, [
1166
+ "label",
1167
+ "value",
1168
+ "max",
1169
+ "readOnly",
1170
+ "onChange",
1171
+ "className",
1172
+ "wrapperClassName"
1173
+ ]);
1174
+ const stars = Array.from({ length: max }, (_, index) => index + 1);
1175
+ return /* @__PURE__ */ jsxs14("div", { className: cn("ph-field", wrapperClassName), children: [
1176
+ label && /* @__PURE__ */ jsx15("span", { className: "ph-label", children: label }),
1177
+ /* @__PURE__ */ jsx15(
1178
+ "div",
1179
+ __spreadProps(__spreadValues({
1180
+ className: cn("ph-rating flex", className),
1181
+ role: readOnly ? "img" : "radiogroup",
1182
+ "aria-label": label != null ? label : `Rating: ${value} out of ${max}`
1183
+ }, props), {
1184
+ children: stars.map((star) => {
1185
+ const active = star <= value;
1186
+ if (readOnly) {
1187
+ return /* @__PURE__ */ jsx15(
1188
+ IconStar,
1189
+ {
1190
+ className: cn("h-6 w-6", active ? "text-amber-500" : "text-ph-border"),
1191
+ "aria-hidden": true
1192
+ },
1193
+ star
1194
+ );
1195
+ }
1196
+ return /* @__PURE__ */ jsx15(
1197
+ "button",
1198
+ {
1199
+ type: "button",
1200
+ className: "rounded p-0.5 transition hover:scale-105 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-brand",
1201
+ role: "radio",
1202
+ "aria-checked": active,
1203
+ "aria-label": `${star} out of ${max}`,
1204
+ onClick: () => onChange == null ? void 0 : onChange(star),
1205
+ children: /* @__PURE__ */ jsx15(IconStar, { className: cn("h-6 w-6", active ? "text-amber-500" : "text-ph-border") })
1206
+ },
1207
+ star
1208
+ );
1209
+ })
1210
+ })
1211
+ )
1212
+ ] });
1213
+ }
1214
+
1215
+ // src/components/ui/SearchInput.tsx
1216
+ import { useId as useId4 } from "react";
1217
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1218
+ function SearchInput(_a) {
1219
+ var _b = _a, {
1220
+ id: idProp,
1221
+ label = "Search",
1222
+ hideLabel = false,
1223
+ shortcut,
1224
+ density = "default",
1225
+ className,
1226
+ wrapperClassName,
1227
+ placeholder
1228
+ } = _b, props = __objRest(_b, [
1229
+ "id",
1230
+ "label",
1231
+ "hideLabel",
1232
+ "shortcut",
1233
+ "density",
1234
+ "className",
1235
+ "wrapperClassName",
1236
+ "placeholder"
1237
+ ]);
1238
+ const autoId = useId4();
1239
+ const id = idProp != null ? idProp : autoId;
1240
+ return /* @__PURE__ */ jsxs15("div", { className: cn("relative", wrapperClassName), children: [
1241
+ /* @__PURE__ */ jsx16("label", { htmlFor: id, className: hideLabel ? "sr-only" : "ph-label mb-1.5 block", children: label }),
1242
+ /* @__PURE__ */ jsxs15("div", { className: "relative", children: [
1243
+ shortcut != null ? /* @__PURE__ */ jsx16(
1244
+ "span",
1245
+ {
1246
+ className: "ph-shortcut pointer-events-none absolute left-3 top-1/2 z-10 -translate-y-1/2 text-xs",
1247
+ "aria-hidden": true,
1248
+ children: shortcut
1249
+ }
1250
+ ) : null,
1251
+ /* @__PURE__ */ jsx16(
1252
+ "input",
1253
+ __spreadValues({
1254
+ id,
1255
+ type: "search",
1256
+ placeholder,
1257
+ "aria-label": hideLabel ? label : void 0,
1258
+ className: cn(
1259
+ "ph-input w-full",
1260
+ density === "compact" && "max-w-xs !min-h-[2rem] py-1.5 text-sm",
1261
+ shortcut != null && "pl-[3.25rem]",
1262
+ className
1263
+ )
1264
+ }, props)
1265
+ )
1266
+ ] })
1267
+ ] });
1268
+ }
1269
+ function SearchGroup(_a) {
1270
+ var _b = _a, {
1271
+ id: idProp,
1272
+ label = "Search records",
1273
+ submitLabel = "Search",
1274
+ placeholder = "Persons, actions, flags\u2026",
1275
+ wrapperClassName,
1276
+ className
1277
+ } = _b, props = __objRest(_b, [
1278
+ "id",
1279
+ "label",
1280
+ "submitLabel",
1281
+ "placeholder",
1282
+ "wrapperClassName",
1283
+ "className"
1284
+ ]);
1285
+ const autoId = useId4();
1286
+ const id = idProp != null ? idProp : autoId;
1287
+ return /* @__PURE__ */ jsxs15("div", { className: cn("ph-field", wrapperClassName), children: [
1288
+ /* @__PURE__ */ jsx16("label", { htmlFor: id, className: "ph-label", children: label }),
1289
+ /* @__PURE__ */ jsxs15("div", { className: "ph-search-group flex w-full max-w-lg min-h-[2.3125rem] items-stretch divide-x divide-ph-border", children: [
1290
+ /* @__PURE__ */ jsx16(
1291
+ "input",
1292
+ __spreadValues({
1293
+ id,
1294
+ type: "search",
1295
+ placeholder,
1296
+ className: cn("ph-input ph-input-group-field min-w-0 flex-1", className)
1297
+ }, props)
1298
+ ),
1299
+ /* @__PURE__ */ jsx16(
1300
+ Button,
1301
+ {
1302
+ type: "submit",
1303
+ variant: "primary",
1304
+ icon: /* @__PURE__ */ jsx16(IconSearch, { className: "h-4 w-4", "aria-hidden": true }),
1305
+ className: "ph-search-group__submit",
1306
+ "aria-label": submitLabel
1307
+ }
1308
+ )
1309
+ ] })
1310
+ ] });
1311
+ }
1312
+
1313
+ // src/components/ui/Table.tsx
1314
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1315
+ function Table({
1316
+ data,
1317
+ columns,
1318
+ zebra = false,
1319
+ compact = false,
1320
+ ribbon = false,
1321
+ getRowStyle,
1322
+ className,
1323
+ caption
1324
+ }) {
1325
+ return /* @__PURE__ */ jsx17("div", { className: cn("ph-table-wrap", compact && "ph-table-compact", className), children: /* @__PURE__ */ jsxs16("table", { className: cn("ph-table", zebra && "ph-table-zebra", ribbon && "ph-table--ribbon"), children: [
1326
+ caption && /* @__PURE__ */ jsx17("caption", { className: "sr-only", children: caption }),
1327
+ /* @__PURE__ */ jsx17("thead", { children: /* @__PURE__ */ jsx17("tr", { children: columns.map((col) => /* @__PURE__ */ jsx17("th", { className: col.className, children: col.header }, col.key)) }) }),
1328
+ /* @__PURE__ */ jsx17("tbody", { children: data.map((row, i) => /* @__PURE__ */ jsx17("tr", { style: getRowStyle == null ? void 0 : getRowStyle(row), children: columns.map((col) => /* @__PURE__ */ jsx17("td", { className: col.className, children: col.cell(row) }, col.key)) }, i)) })
1329
+ ] }) });
1330
+ }
1331
+
1332
+ // src/components/ui/Stat.tsx
1333
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
1334
+ var toneMap = {
1335
+ default: "text-ph-ink",
1336
+ brand: "text-ph-brand",
1337
+ blue: "text-ph-blue",
1338
+ purple: "text-ph-purple",
1339
+ warning: "text-amber-900"
1340
+ };
1341
+ var statMap = {
1342
+ default: "",
1343
+ brand: "",
1344
+ blue: "",
1345
+ purple: "",
1346
+ warning: "border-amber-200 bg-amber-50/70"
1347
+ };
1348
+ function Stat(_a) {
1349
+ var _b = _a, { icon, label, value, footer, tone = "default", className } = _b, props = __objRest(_b, ["icon", "label", "value", "footer", "tone", "className"]);
1350
+ return /* @__PURE__ */ jsxs17("article", __spreadProps(__spreadValues({ className: cn("ph-stat", statMap[tone], className) }, props), { children: [
1351
+ icon && /* @__PURE__ */ jsx18("div", { className: cn("mb-2 h-7 w-7", toneMap[tone]), children: icon }),
1352
+ /* @__PURE__ */ jsx18("div", { className: cn("ph-stat-label", tone === "warning" && toneMap[tone]), children: label }),
1353
+ /* @__PURE__ */ jsx18("div", { className: cn("ph-stat-val", toneMap[tone]), children: value }),
1354
+ footer && /* @__PURE__ */ jsx18("p", { className: "text-xs text-ph-subtle", children: footer })
1355
+ ] }));
1356
+ }
1357
+
1358
+ // src/components/ui/Toast.tsx
1359
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1360
+ var statusConfig2 = {
1361
+ info: { icon: IconErrorOutline, color: "text-ph-info", bg: "ph-toast-info" },
1362
+ success: { icon: IconCheckCircle, color: "text-ph-success", bg: "ph-toast-success" },
1363
+ warning: { icon: IconExclamation, color: "text-ph-warning", bg: "ph-toast-warning" },
1364
+ danger: { icon: IconCancel, color: "text-ph-danger", bg: "ph-toast-danger" }
1365
+ };
1366
+ function Toast({
1367
+ status = "info",
1368
+ title,
1369
+ description,
1370
+ onDismiss,
1371
+ className
1372
+ }) {
1373
+ const config = statusConfig2[status];
1374
+ const Icon = config.icon;
1375
+ return /* @__PURE__ */ jsxs18("div", { className: cn("ph-toast", config.bg, className), children: [
1376
+ /* @__PURE__ */ jsx19(Icon, { className: cn("mt-0.5 h-5 w-5 shrink-0", config.color), "aria-hidden": true }),
1377
+ /* @__PURE__ */ jsxs18("div", { className: "pr-8", children: [
1378
+ /* @__PURE__ */ jsx19("div", { className: "font-semibold", children: title }),
1379
+ description && /* @__PURE__ */ jsx19("p", { className: "mt-1 text-xs text-ph-subtle", children: description })
1380
+ ] }),
1381
+ onDismiss && /* @__PURE__ */ jsx19(
1382
+ "button",
1383
+ {
1384
+ type: "button",
1385
+ "aria-label": `Dismiss ${title}`,
1386
+ className: "absolute right-2 top-2 ph-btn ph-btn-ghost ph-btn-xs ph-btn-circle",
1387
+ onClick: onDismiss,
1388
+ children: /* @__PURE__ */ jsx19(IconClose, { className: "h-4 w-4" })
1389
+ }
1390
+ )
1391
+ ] });
1392
+ }
1393
+ function ToastStack({ children, className }) {
1394
+ return /* @__PURE__ */ jsx19("div", { className: cn("ph-toast-stack", className), children });
1395
+ }
1396
+
1397
+ // src/components/ui/Tabs.tsx
1398
+ import { jsx as jsx20 } from "react/jsx-runtime";
1399
+ function Tabs({ items, value, onChange, variant = "pill", className }) {
1400
+ if (variant === "underline") {
1401
+ return /* @__PURE__ */ jsx20("div", { className: cn("flex gap-6 border-b border-ph-border", className), children: items.map((item) => /* @__PURE__ */ jsx20(
1402
+ "button",
1403
+ {
1404
+ type: "button",
1405
+ onClick: () => onChange(item.value),
1406
+ className: cn(
1407
+ "-mb-px border-b-2 pb-2 text-sm font-semibold transition",
1408
+ value === item.value ? "border-ph-brand text-ph-ink" : "border-transparent text-ph-mutedtext hover:text-ph-ink"
1409
+ ),
1410
+ children: item.label
1411
+ },
1412
+ item.value
1413
+ )) });
1414
+ }
1415
+ return /* @__PURE__ */ jsx20("div", { className: cn("ph-tabs-row inline-flex", className), children: items.map((item) => /* @__PURE__ */ jsx20(
1416
+ "button",
1417
+ {
1418
+ type: "button",
1419
+ onClick: () => onChange(item.value),
1420
+ className: cn("ph-tab", value === item.value && "ph-tab-active"),
1421
+ children: item.label
1422
+ },
1423
+ item.value
1424
+ )) });
1425
+ }
1426
+
1427
+ // src/components/ui/ThemeDomSync.tsx
1428
+ import { useLayoutEffect } from "react";
1429
+
1430
+ // src/themes/registry.ts
1431
+ var DEFAULT_THEME_ID = "hedgehog-light";
1432
+ var THEMES = [
1433
+ {
1434
+ id: "hedgehog-light",
1435
+ name: "HedgeHog Light",
1436
+ description: "Default Quill warm greys and orange Lemon chrome.",
1437
+ colorScheme: "light",
1438
+ group: "HedgeHog"
1439
+ },
1440
+ {
1441
+ id: "hedgehog-dark",
1442
+ name: "HedgeHog Dark",
1443
+ description: "Dark app shell with HedgeHog orange accents.",
1444
+ colorScheme: "dark",
1445
+ group: "HedgeHog"
1446
+ },
1447
+ {
1448
+ id: "catppuccin-light",
1449
+ name: "Catppuccin Light",
1450
+ description: "Catppuccin Latte \u2014 soft pastels and mauve accent.",
1451
+ colorScheme: "light",
1452
+ group: "Catppuccin"
1453
+ },
1454
+ {
1455
+ id: "catppuccin-dark",
1456
+ name: "Catppuccin Dark",
1457
+ description: "Catppuccin Mocha \u2014 deep base and lavender peach.",
1458
+ colorScheme: "dark",
1459
+ group: "Catppuccin"
1460
+ },
1461
+ {
1462
+ id: "sheets",
1463
+ name: "Sheets",
1464
+ description: "Spreadsheet green on office neutrals.",
1465
+ colorScheme: "light",
1466
+ group: "Productivity"
1467
+ },
1468
+ {
1469
+ id: "sheets-dark",
1470
+ name: "Sheets Dark",
1471
+ description: "Dark shell with spreadsheet green accent.",
1472
+ colorScheme: "dark",
1473
+ group: "Productivity"
1474
+ },
1475
+ {
1476
+ id: "note",
1477
+ name: "Note",
1478
+ description: "Notebook purple on lavender-white chrome.",
1479
+ colorScheme: "light",
1480
+ group: "Productivity"
1481
+ },
1482
+ {
1483
+ id: "note-dark",
1484
+ name: "Note Dark",
1485
+ description: "Dark notebook purple \u2014 night reading mode.",
1486
+ colorScheme: "dark",
1487
+ group: "Productivity"
1488
+ },
1489
+ {
1490
+ id: "presentation",
1491
+ name: "Presentation",
1492
+ description: "Orange-red on office neutrals.",
1493
+ colorScheme: "light",
1494
+ group: "Productivity"
1495
+ },
1496
+ {
1497
+ id: "presentation-dark",
1498
+ name: "Presentation Dark",
1499
+ description: "Dark shell with orange-red accent.",
1500
+ colorScheme: "dark",
1501
+ group: "Productivity"
1502
+ },
1503
+ {
1504
+ id: "socials",
1505
+ name: "Socials",
1506
+ description: "Meta blue accent on familiar social greys.",
1507
+ colorScheme: "light",
1508
+ group: "Social"
1509
+ },
1510
+ {
1511
+ id: "socials-dark",
1512
+ name: "Socials Dark",
1513
+ description: "Social dark mode \u2014 #18191A base and Meta blue.",
1514
+ colorScheme: "dark",
1515
+ group: "Social"
1516
+ },
1517
+ {
1518
+ id: "chats-light",
1519
+ name: "Chats Light",
1520
+ description: "Aubergine brand on clean workspace neutrals.",
1521
+ colorScheme: "light",
1522
+ group: "Chats"
1523
+ },
1524
+ {
1525
+ id: "chats-dark",
1526
+ name: "Chats Dark",
1527
+ description: "Dark sidebar \u2014 #1A1D21 base and green highlights.",
1528
+ colorScheme: "dark",
1529
+ group: "Chats"
1530
+ },
1531
+ {
1532
+ id: "xenide-light",
1533
+ name: "Xenide Light",
1534
+ description: "xenide.io light \u2014 Excel green + purple on neutral greys.",
1535
+ colorScheme: "light",
1536
+ group: "Xenide"
1537
+ },
1538
+ {
1539
+ id: "xenide-dark",
1540
+ name: "Xenide Dark",
1541
+ description: "xenide.io dark \u2014 #0A0A0F base, emerald green + violet.",
1542
+ colorScheme: "dark",
1543
+ group: "Xenide"
1544
+ },
1545
+ {
1546
+ id: "bikini-bottom",
1547
+ name: "Bikini Bottom",
1548
+ description: "SpongeBob palette \u2014 ocean canvas, readable surfaces, character accents.",
1549
+ colorScheme: "light",
1550
+ group: "Fun"
1551
+ },
1552
+ {
1553
+ id: "bikini-bottom-dark",
1554
+ name: "Bikini Bottom Dark",
1555
+ description: "Bikini Bottom at night \u2014 deep ocean with neon character accents.",
1556
+ colorScheme: "dark",
1557
+ group: "Fun"
1558
+ },
1559
+ {
1560
+ id: "turtletime",
1561
+ name: "TurtleTime",
1562
+ description: "Turtle mascot palette \u2014 shell orange, leaf green, and warm cream.",
1563
+ colorScheme: "light",
1564
+ group: "Fun"
1565
+ },
1566
+ {
1567
+ id: "turtletime-dark",
1568
+ name: "TurtleTime Dark",
1569
+ description: "TurtleTime after dusk \u2014 dark olive shell with bright orange clock accents.",
1570
+ colorScheme: "dark",
1571
+ group: "Fun"
1572
+ },
1573
+ {
1574
+ id: "github-light",
1575
+ name: "GitHub Light",
1576
+ description: "GitHub Primer \u2014 #f6f8fa canvas and emphasis blue accents.",
1577
+ colorScheme: "light",
1578
+ group: "GitHub"
1579
+ },
1580
+ {
1581
+ id: "github-dark",
1582
+ name: "GitHub Dark",
1583
+ description: "GitHub dark dimmed \u2014 #0d1117 base and #4493f8 links.",
1584
+ colorScheme: "dark",
1585
+ group: "GitHub"
1586
+ },
1587
+ {
1588
+ id: "rosepine-light",
1589
+ name: "Ros\xE9 Pine Dawn",
1590
+ description: "Ros\xE9 Pine Dawn \u2014 warm paper base with muted iris accents.",
1591
+ colorScheme: "light",
1592
+ group: "Ros\xE9 Pine"
1593
+ },
1594
+ {
1595
+ id: "rosepine-dark",
1596
+ name: "Ros\xE9 Pine",
1597
+ description: "Ros\xE9 Pine Main \u2014 moonlit base with iris and love accents.",
1598
+ colorScheme: "dark",
1599
+ group: "Ros\xE9 Pine"
1600
+ },
1601
+ {
1602
+ id: "notion",
1603
+ name: "Notion",
1604
+ description: "Notion light \u2014 warm off-white canvas, Notion blue accent, signature dark text.",
1605
+ colorScheme: "light",
1606
+ group: "Productivity"
1607
+ },
1608
+ {
1609
+ id: "notion-dark",
1610
+ name: "Notion Dark",
1611
+ description: "Notion dark mode \u2014 dark charcoal canvas with blue accent and clean typography.",
1612
+ colorScheme: "dark",
1613
+ group: "Productivity"
1614
+ },
1615
+ {
1616
+ id: "deepsea-light",
1617
+ name: "Tokyo Night Day",
1618
+ description: "Tokyo Night Day \u2014 soft bluish greys with vivid blue and purple accents.",
1619
+ colorScheme: "light",
1620
+ group: "Tokyo Night"
1621
+ },
1622
+ {
1623
+ id: "deepsea-dark",
1624
+ name: "Tokyo Night",
1625
+ description: "Tokyo Night \u2014 #1a1b26 base with signature blue, cyan, and purple.",
1626
+ colorScheme: "dark",
1627
+ group: "Tokyo Night"
1628
+ },
1629
+ {
1630
+ id: "kraken-light",
1631
+ name: "Kraken Light",
1632
+ description: "Medium-inspired warm paper, editorial black actions, and classic publication yellow.",
1633
+ colorScheme: "light",
1634
+ group: "Kraken"
1635
+ },
1636
+ {
1637
+ id: "kraken-dark",
1638
+ name: "Kraken Dark",
1639
+ description: "Medium-inspired night reading canvas with white actions and classic publication yellow.",
1640
+ colorScheme: "dark",
1641
+ group: "Kraken"
1642
+ }
1643
+ ];
1644
+ var THEME_GROUPS = Array.from(new Set(THEMES.map((theme) => theme.group)));
1645
+ function isThemeId(value) {
1646
+ return THEMES.some((theme) => theme.id === value);
1647
+ }
1648
+ function getTheme(id) {
1649
+ return THEMES.find((theme) => theme.id === id);
1650
+ }
1651
+
1652
+ // src/themes/init-theme.ts
1653
+ var STORAGE_KEY = "ph-theme";
1654
+ var VALID_THEMES = THEMES.map((theme) => theme.id);
1655
+ 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==="xenide")t="xenide-light";if(!t||v.indexOf(t)<0)t=d;document.documentElement.setAttribute("data-theme",t)}catch(e){document.documentElement.setAttribute("data-theme","${DEFAULT_THEME_ID}")}})();`;
1656
+ function persistTheme(themeId) {
1657
+ if (typeof window === "undefined") {
1658
+ return;
1659
+ }
1660
+ if (!isThemeId(themeId)) {
1661
+ return;
1662
+ }
1663
+ document.documentElement.setAttribute("data-theme", themeId);
1664
+ localStorage.setItem(STORAGE_KEY, themeId);
1665
+ }
1666
+ function readStoredTheme() {
1667
+ if (typeof window === "undefined") {
1668
+ return DEFAULT_THEME_ID;
1669
+ }
1670
+ const stored = localStorage.getItem(STORAGE_KEY);
1671
+ if (stored === "xenide") {
1672
+ return "xenide-light";
1673
+ }
1674
+ return stored && isThemeId(stored) ? stored : DEFAULT_THEME_ID;
1675
+ }
1676
+
1677
+ // src/components/ui/ThemeDomSync.tsx
1678
+ function ThemeDomSync() {
1679
+ useLayoutEffect(() => {
1680
+ persistTheme(readStoredTheme());
1681
+ }, []);
1682
+ return null;
1683
+ }
1684
+
1685
+ // src/components/ui/ThemeManager.tsx
1686
+ import { useLayoutEffect as useLayoutEffect2 } from "react";
1687
+ import { Fragment as Fragment3, jsx as jsx21 } from "react/jsx-runtime";
1688
+ function ThemeManager({ children }) {
1689
+ useLayoutEffect2(() => {
1690
+ persistTheme(readStoredTheme());
1691
+ }, []);
1692
+ return /* @__PURE__ */ jsx21(Fragment3, { children });
1693
+ }
1694
+
1695
+ // src/components/ui/ThemeSwitcher.tsx
1696
+ import { useEffect, useState } from "react";
1697
+ import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
1698
+ function ThemeSwitcher({ className }) {
1699
+ const [themeId, setThemeId] = useState("hedgehog-light");
1700
+ useEffect(() => {
1701
+ const id = readStoredTheme();
1702
+ persistTheme(id);
1703
+ setThemeId(id);
1704
+ }, []);
1705
+ return /* @__PURE__ */ jsxs19("label", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1706
+ /* @__PURE__ */ jsx22("span", { className: "shrink-0 text-xs font-medium text-ph-mutedtext sm:text-sm", children: "Theme" }),
1707
+ /* @__PURE__ */ jsx22(
1708
+ "select",
1709
+ {
1710
+ 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",
1711
+ value: themeId,
1712
+ "aria-label": "Colour theme",
1713
+ onChange: (event) => {
1714
+ const next = event.target.value;
1715
+ persistTheme(next);
1716
+ setThemeId(next);
1717
+ },
1718
+ children: THEME_GROUPS.map((group) => /* @__PURE__ */ jsx22("optgroup", { label: group, children: THEMES.filter((theme) => theme.group === group).map((theme) => /* @__PURE__ */ jsx22("option", { value: theme.id, children: theme.name }, theme.id)) }, group))
1719
+ }
1720
+ )
1721
+ ] });
1722
+ }
1723
+
1724
+ // src/components/ui/Accordion.tsx
1725
+ import { useState as useState2 } from "react";
1726
+ import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
1727
+ function Accordion({
1728
+ items,
1729
+ allowMultiple = false,
1730
+ defaultOpen = [],
1731
+ className
1732
+ }) {
1733
+ const [openItems, setOpenItems] = useState2(new Set(defaultOpen));
1734
+ const toggleItem = (id) => {
1735
+ setOpenItems((prev) => {
1736
+ const next = new Set(prev);
1737
+ if (next.has(id)) {
1738
+ next.delete(id);
1739
+ } else {
1740
+ if (!allowMultiple) {
1741
+ next.clear();
1742
+ }
1743
+ next.add(id);
1744
+ }
1745
+ return next;
1746
+ });
1747
+ };
1748
+ return /* @__PURE__ */ jsx23("div", { className: cn("divide-y divide-ph-border rounded-xl border border-ph-border bg-ph-surface", className), children: items.map((item) => {
1749
+ const isOpen = openItems.has(item.id);
1750
+ return /* @__PURE__ */ jsxs20("div", { className: "first:rounded-t-xl last:rounded-b-xl", children: [
1751
+ /* @__PURE__ */ jsxs20(
1752
+ "button",
1753
+ {
1754
+ type: "button",
1755
+ onClick: () => toggleItem(item.id),
1756
+ className: "flex w-full items-center justify-between px-5 py-4 text-left transition hover:bg-ph-muted",
1757
+ children: [
1758
+ /* @__PURE__ */ jsx23("span", { className: "font-semibold text-ph-ink", children: item.title }),
1759
+ /* @__PURE__ */ jsx23(
1760
+ IconChevronDown,
1761
+ {
1762
+ className: cn(
1763
+ "h-5 w-5 text-ph-mutedtext transition-transform duration-200",
1764
+ isOpen && "rotate-180"
1765
+ )
1766
+ }
1767
+ )
1768
+ ]
1769
+ }
1770
+ ),
1771
+ /* @__PURE__ */ jsx23(
1772
+ "div",
1773
+ {
1774
+ className: cn(
1775
+ "grid transition-all duration-200",
1776
+ isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
1777
+ ),
1778
+ children: /* @__PURE__ */ jsx23("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx23("div", { className: "px-5 pb-4 text-ph-subtle", children: item.content }) })
1779
+ }
1780
+ )
1781
+ ] }, item.id);
1782
+ }) });
1783
+ }
1784
+
1785
+ // src/components/ui/Stepper.tsx
1786
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
1787
+ function Stepper({ steps, currentStep, className }) {
1788
+ return /* @__PURE__ */ jsx24("div", { className: cn("flex items-start gap-2", className), children: steps.map((step, index) => {
1789
+ const isCompleted = index < currentStep;
1790
+ const isCurrent = index === currentStep;
1791
+ const isPending = index > currentStep;
1792
+ const isError = step.status === "error";
1793
+ return /* @__PURE__ */ jsxs21("div", { className: "flex flex-1 items-start gap-2", children: [
1794
+ /* @__PURE__ */ jsxs21("div", { className: "flex flex-1 flex-col items-center", children: [
1795
+ /* @__PURE__ */ jsx24(
1796
+ "div",
1797
+ {
1798
+ className: cn(
1799
+ "flex h-9 w-9 items-center justify-center rounded-full text-sm font-bold transition-colors",
1800
+ isCompleted && "bg-ph-success text-[var(--ph-on-success)]",
1801
+ isCurrent && !isError && "bg-ph-brand text-[var(--ph-on-accent)] ring-4 ring-ph-brand/20",
1802
+ isCurrent && isError && "bg-ph-danger text-[var(--ph-on-danger)]",
1803
+ isPending && "bg-ph-muted text-ph-mutedtext"
1804
+ ),
1805
+ children: isCompleted ? /* @__PURE__ */ jsx24(IconCheck, { className: "h-5 w-5", "aria-hidden": true }) : index + 1
1806
+ }
1807
+ ),
1808
+ /* @__PURE__ */ jsxs21("div", { className: "mt-2 text-center", children: [
1809
+ /* @__PURE__ */ jsx24(
1810
+ "p",
1811
+ {
1812
+ className: cn(
1813
+ "text-sm font-semibold",
1814
+ isCurrent && "text-ph-ink",
1815
+ !isCurrent && "text-ph-mutedtext"
1816
+ ),
1817
+ children: step.label
1818
+ }
1819
+ ),
1820
+ step.description && /* @__PURE__ */ jsx24("p", { className: "mt-0.5 text-xs text-ph-mutedtext", children: step.description })
1821
+ ] })
1822
+ ] }),
1823
+ index < steps.length - 1 && /* @__PURE__ */ jsx24(
1824
+ "div",
1825
+ {
1826
+ className: cn(
1827
+ "mt-4 h-0.5 flex-1 rounded-full transition-colors",
1828
+ isCompleted ? "bg-ph-success" : "bg-ph-border"
1829
+ )
1830
+ }
1831
+ )
1832
+ ] }, step.id);
1833
+ }) });
1834
+ }
1835
+
1836
+ // src/components/ui/SegmentedControl.tsx
1837
+ import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
1838
+ function SegmentedControl({ options, value, onChange, className }) {
1839
+ return /* @__PURE__ */ jsx25(
1840
+ "div",
1841
+ {
1842
+ className: cn(
1843
+ "inline-flex rounded-lg bg-ph-muted p-1",
1844
+ className
1845
+ ),
1846
+ children: options.map((option) => /* @__PURE__ */ jsxs22(
1847
+ "button",
1848
+ {
1849
+ type: "button",
1850
+ onClick: () => onChange(option.value),
1851
+ className: cn(
1852
+ "relative flex items-center gap-1.5 rounded-md px-3.5 py-1.5 text-sm font-medium transition-all",
1853
+ value === option.value ? "bg-ph-surface text-ph-ink shadow-ph" : "text-ph-subtle hover:text-ph-ink"
1854
+ ),
1855
+ children: [
1856
+ option.icon && /* @__PURE__ */ jsx25("span", { className: "h-4 w-4", children: option.icon }),
1857
+ option.label
1858
+ ]
1859
+ },
1860
+ option.value
1861
+ ))
1862
+ }
1863
+ );
1864
+ }
1865
+
1866
+ // src/components/ui/CommandPalette.tsx
1867
+ import { useState as useState3, useEffect as useEffect2, useRef as useRef2 } from "react";
1868
+ import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
1869
+ function CommandPalette({
1870
+ items,
1871
+ isOpen,
1872
+ onClose,
1873
+ placeholder = "Type a command or search...",
1874
+ className
1875
+ }) {
1876
+ const [query, setQuery] = useState3("");
1877
+ const [selectedIndex, setSelectedIndex] = useState3(0);
1878
+ const inputRef = useRef2(null);
1879
+ const filtered = items.filter(
1880
+ (item) => item.label.toLowerCase().includes(query.toLowerCase())
1881
+ );
1882
+ useEffect2(() => {
1883
+ var _a;
1884
+ if (isOpen) {
1885
+ setQuery("");
1886
+ setSelectedIndex(0);
1887
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
1888
+ }
1889
+ }, [isOpen]);
1890
+ useEffect2(() => {
1891
+ const handleKeyDown = (e) => {
1892
+ var _a;
1893
+ if (!isOpen) return;
1894
+ switch (e.key) {
1895
+ case "ArrowDown":
1896
+ e.preventDefault();
1897
+ setSelectedIndex((i) => (i + 1) % filtered.length);
1898
+ break;
1899
+ case "ArrowUp":
1900
+ e.preventDefault();
1901
+ setSelectedIndex((i) => (i - 1 + filtered.length) % filtered.length);
1902
+ break;
1903
+ case "Enter":
1904
+ e.preventDefault();
1905
+ (_a = filtered[selectedIndex]) == null ? void 0 : _a.onSelect();
1906
+ onClose();
1907
+ break;
1908
+ case "Escape":
1909
+ onClose();
1910
+ break;
1911
+ }
1912
+ };
1913
+ window.addEventListener("keydown", handleKeyDown);
1914
+ return () => window.removeEventListener("keydown", handleKeyDown);
1915
+ }, [isOpen, filtered, selectedIndex, onClose]);
1916
+ if (!isOpen) return null;
1917
+ return /* @__PURE__ */ jsx26("div", { className: "fixed inset-0 z-50 flex items-start justify-center bg-black/40 pt-[20vh] backdrop-blur-sm", children: /* @__PURE__ */ jsxs23(
1918
+ "div",
1919
+ {
1920
+ className: cn(
1921
+ "w-full max-w-xl overflow-hidden rounded-xl border border-ph-border bg-ph-surface shadow-ph-md",
1922
+ className
1923
+ ),
1924
+ children: [
1925
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
1926
+ /* @__PURE__ */ jsx26(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
1927
+ /* @__PURE__ */ jsx26(
1928
+ "input",
1929
+ {
1930
+ ref: inputRef,
1931
+ type: "text",
1932
+ value: query,
1933
+ onChange: (e) => {
1934
+ setQuery(e.target.value);
1935
+ setSelectedIndex(0);
1936
+ },
1937
+ placeholder,
1938
+ className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
1939
+ }
1940
+ ),
1941
+ /* @__PURE__ */ jsx26("kbd", { className: "rounded border border-ph-border bg-ph-muted px-1.5 py-0.5 text-xs text-ph-mutedtext", children: "ESC" })
1942
+ ] }),
1943
+ /* @__PURE__ */ jsx26("div", { className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ jsx26("div", { className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ jsxs23(
1944
+ "button",
1945
+ {
1946
+ type: "button",
1947
+ onClick: () => {
1948
+ item.onSelect();
1949
+ onClose();
1950
+ },
1951
+ onMouseEnter: () => setSelectedIndex(index),
1952
+ className: cn(
1953
+ "flex w-full items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
1954
+ index === selectedIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
1955
+ ),
1956
+ children: [
1957
+ item.icon && /* @__PURE__ */ jsx26("span", { className: "h-5 w-5", children: item.icon }),
1958
+ /* @__PURE__ */ jsx26("span", { className: "flex-1", children: item.label }),
1959
+ item.shortcut && /* @__PURE__ */ jsx26("kbd", { className: "rounded border border-ph-border bg-ph-surface px-1.5 py-0.5 text-xs text-ph-mutedtext", children: item.shortcut })
1960
+ ]
1961
+ },
1962
+ item.id
1963
+ )) })
1964
+ ]
1965
+ }
1966
+ ) });
1967
+ }
1968
+
1969
+ // src/components/ui/Calendar.tsx
1970
+ import { useState as useState4 } from "react";
1971
+ import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
1972
+ function Calendar({ value, onChange, className }) {
1973
+ const [currentMonth, setCurrentMonth] = useState4(value || /* @__PURE__ */ new Date());
1974
+ const today = /* @__PURE__ */ new Date();
1975
+ const year = currentMonth.getFullYear();
1976
+ const month = currentMonth.getMonth();
1977
+ const firstDay = new Date(year, month, 1).getDay();
1978
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
1979
+ const prevMonth = () => setCurrentMonth(new Date(year, month - 1, 1));
1980
+ const nextMonth = () => setCurrentMonth(new Date(year, month + 1, 1));
1981
+ const monthNames = [
1982
+ "January",
1983
+ "February",
1984
+ "March",
1985
+ "April",
1986
+ "May",
1987
+ "June",
1988
+ "July",
1989
+ "August",
1990
+ "September",
1991
+ "October",
1992
+ "November",
1993
+ "December"
1994
+ ];
1995
+ const weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
1996
+ const isSelected = (day) => {
1997
+ if (!value) return false;
1998
+ return value.getDate() === day && value.getMonth() === month && value.getFullYear() === year;
1999
+ };
2000
+ const isToday = (day) => {
2001
+ return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
2002
+ };
2003
+ const handleSelect = (day) => {
2004
+ onChange == null ? void 0 : onChange(new Date(year, month, day));
2005
+ };
2006
+ const days = [];
2007
+ for (let i = 0; i < firstDay; i++) {
2008
+ days.push(null);
2009
+ }
2010
+ for (let i = 1; i <= daysInMonth; i++) {
2011
+ days.push(i);
2012
+ }
2013
+ return /* @__PURE__ */ jsxs24("div", { className: cn("w-[280px] rounded-xl border border-ph-border bg-ph-surface p-4 shadow-ph", className), children: [
2014
+ /* @__PURE__ */ jsxs24("div", { className: "mb-4 flex items-center justify-between", children: [
2015
+ /* @__PURE__ */ jsx27(
2016
+ "button",
2017
+ {
2018
+ type: "button",
2019
+ onClick: prevMonth,
2020
+ "aria-label": "Previous month",
2021
+ className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
2022
+ children: /* @__PURE__ */ jsx27(IconChevronLeft, { className: "h-5 w-5", "aria-hidden": true })
2023
+ }
2024
+ ),
2025
+ /* @__PURE__ */ jsxs24("span", { className: "text-sm font-semibold text-ph-ink", children: [
2026
+ monthNames[month],
2027
+ " ",
2028
+ year
2029
+ ] }),
2030
+ /* @__PURE__ */ jsx27(
2031
+ "button",
2032
+ {
2033
+ type: "button",
2034
+ onClick: nextMonth,
2035
+ "aria-label": "Next month",
2036
+ className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
2037
+ children: /* @__PURE__ */ jsx27(IconChevronRight, { className: "h-5 w-5", "aria-hidden": true })
2038
+ }
2039
+ )
2040
+ ] }),
2041
+ /* @__PURE__ */ jsxs24("div", { className: "grid grid-cols-7 gap-1", children: [
2042
+ weekDays.map((day) => /* @__PURE__ */ jsx27("div", { className: "py-1 text-center text-xs font-medium text-ph-mutedtext", children: day }, day)),
2043
+ days.map((day, index) => /* @__PURE__ */ jsx27("div", { className: "aspect-square", children: day && /* @__PURE__ */ jsx27(
2044
+ "button",
2045
+ {
2046
+ type: "button",
2047
+ onClick: () => handleSelect(day),
2048
+ className: cn(
2049
+ "flex h-full w-full items-center justify-center rounded-lg text-sm transition-colors",
2050
+ 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"
2051
+ ),
2052
+ children: day
2053
+ }
2054
+ ) }, index))
2055
+ ] })
2056
+ ] });
2057
+ }
2058
+
2059
+ // src/components/ui/HoverCard.tsx
2060
+ import { useState as useState5 } from "react";
2061
+ import { jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
2062
+ function HoverCard({ trigger, children, className }) {
2063
+ const [isVisible, setIsVisible] = useState5(false);
2064
+ return /* @__PURE__ */ jsxs25(
2065
+ "div",
2066
+ {
2067
+ className: "relative inline-block",
2068
+ onMouseEnter: () => setIsVisible(true),
2069
+ onMouseLeave: () => setIsVisible(false),
2070
+ children: [
2071
+ trigger,
2072
+ /* @__PURE__ */ jsxs25(
2073
+ "div",
2074
+ {
2075
+ className: cn(
2076
+ "absolute left-1/2 top-full z-50 mt-2 w-64 -translate-x-1/2 rounded-lg border border-ph-border bg-ph-surface p-4 shadow-ph-md transition-all duration-150",
2077
+ isVisible ? "visible translate-y-0 opacity-100" : "invisible -translate-y-1 opacity-0",
2078
+ className
2079
+ ),
2080
+ children: [
2081
+ /* @__PURE__ */ jsx28("div", { className: "absolute -top-1.5 left-1/2 h-3 w-3 -translate-x-1/2 rotate-45 border-l border-t border-ph-border bg-ph-surface" }),
2082
+ /* @__PURE__ */ jsx28("div", { className: "relative", children })
2083
+ ]
2084
+ }
2085
+ )
2086
+ ]
2087
+ }
2088
+ );
2089
+ }
2090
+
2091
+ // src/components/ui/EmptyState.tsx
2092
+ import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
2093
+ function EmptyState({ icon, title, description, action, className }) {
2094
+ return /* @__PURE__ */ jsxs26(
2095
+ "div",
2096
+ {
2097
+ className: cn(
2098
+ "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",
2099
+ className
2100
+ ),
2101
+ children: [
2102
+ icon && /* @__PURE__ */ jsx29("div", { className: "mb-4 flex h-14 w-14 items-center justify-center rounded-full bg-ph-muted text-ph-mutedtext", children: icon }),
2103
+ /* @__PURE__ */ jsx29("h3", { className: "text-base font-semibold text-ph-ink", children: title }),
2104
+ description && /* @__PURE__ */ jsx29("p", { className: "mt-1 max-w-sm text-sm text-ph-subtle", children: description }),
2105
+ action && /* @__PURE__ */ jsx29("div", { className: "mt-4", children: action })
2106
+ ]
2107
+ }
2108
+ );
2109
+ }
2110
+
2111
+ // src/components/ui/FilterChips.tsx
2112
+ import { Fragment as Fragment4, jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
2113
+ function FilterChips({
2114
+ chips,
2115
+ onToggle,
2116
+ onRemove,
2117
+ className,
2118
+ "aria-label": ariaLabel = "Applied filters"
2119
+ }) {
2120
+ return /* @__PURE__ */ jsx30("div", { className: cn("ph-filter-chips", className), role: "group", "aria-label": ariaLabel, children: chips.map((chip) => {
2121
+ var _a;
2122
+ const label = (_a = chip.removeLabel) != null ? _a : getChipText(chip);
2123
+ const content = /* @__PURE__ */ jsxs27(Fragment4, { children: [
2124
+ /* @__PURE__ */ jsx30("span", { className: "ph-filter-chip__label", children: chip.label }),
2125
+ chip.value != null ? /* @__PURE__ */ jsx30("span", { className: "ph-filter-chip__value", children: chip.value }) : null
2126
+ ] });
2127
+ return /* @__PURE__ */ jsxs27(
2128
+ "span",
2129
+ {
2130
+ className: cn("ph-filter-chip", chip.active && "ph-filter-chip--active"),
2131
+ "data-state": chip.active ? "on" : "off",
2132
+ children: [
2133
+ onToggle ? /* @__PURE__ */ jsx30(
2134
+ "button",
2135
+ {
2136
+ type: "button",
2137
+ className: "ph-filter-chip__main",
2138
+ "aria-pressed": Boolean(chip.active),
2139
+ onClick: () => onToggle(chip.id),
2140
+ children: content
2141
+ }
2142
+ ) : /* @__PURE__ */ jsx30("span", { className: "ph-filter-chip__main", children: content }),
2143
+ chip.active && onRemove ? /* @__PURE__ */ jsx30(
2144
+ "button",
2145
+ {
2146
+ type: "button",
2147
+ className: "ph-filter-chip__remove",
2148
+ "aria-label": `Remove ${label} filter`,
2149
+ onClick: () => onRemove(chip.id),
2150
+ children: /* @__PURE__ */ jsx30(IconClose, { className: "h-3 w-3", "aria-hidden": true })
2151
+ }
2152
+ ) : null
2153
+ ]
2154
+ },
2155
+ chip.id
2156
+ );
2157
+ }) });
2158
+ }
2159
+ function getChipText(chip) {
2160
+ const label = typeof chip.label === "string" || typeof chip.label === "number" ? String(chip.label) : chip.id;
2161
+ const value = typeof chip.value === "string" || typeof chip.value === "number" ? String(chip.value) : null;
2162
+ return value ? `${label}: ${value}` : label;
2163
+ }
2164
+
2165
+ // src/components/ui/FilterBar.tsx
2166
+ import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
2167
+ function FilterBar(_a) {
2168
+ var _b = _a, {
2169
+ children,
2170
+ label = "Filters and sorting",
2171
+ onClear,
2172
+ clearLabel = "Clear all",
2173
+ resultCount,
2174
+ className
2175
+ } = _b, props = __objRest(_b, [
2176
+ "children",
2177
+ "label",
2178
+ "onClear",
2179
+ "clearLabel",
2180
+ "resultCount",
2181
+ "className"
2182
+ ]);
2183
+ return /* @__PURE__ */ jsxs28("div", __spreadProps(__spreadValues({ className: cn("ph-filter-bar", className) }, props), { children: [
2184
+ /* @__PURE__ */ jsxs28("div", { className: "ph-filter-bar__controls", role: "group", "aria-label": label, children: [
2185
+ children,
2186
+ onClear ? /* @__PURE__ */ jsx31("button", { type: "button", className: "ph-filter-bar__clear", onClick: onClear, children: clearLabel }) : null
2187
+ ] }),
2188
+ resultCount != null ? /* @__PURE__ */ jsx31("output", { className: "ph-filter-bar__results", "aria-live": "polite", children: resultCount }) : null
2189
+ ] }));
2190
+ }
2191
+ function FilterMenu({
2192
+ label,
2193
+ value,
2194
+ options,
2195
+ onValueChange,
2196
+ placeholder = "Any",
2197
+ align = "start",
2198
+ disabled,
2199
+ className
2200
+ }) {
2201
+ var _a;
2202
+ const selected = options.find((option) => option.value === value);
2203
+ const displayValue = (_a = selected == null ? void 0 : selected.label) != null ? _a : placeholder;
2204
+ const accessibleValue = selected ? getOptionText(selected) : String(placeholder);
2205
+ return /* @__PURE__ */ jsx31(
2206
+ DropdownMenu,
2207
+ {
2208
+ "aria-label": `${label}: ${accessibleValue}`,
2209
+ align,
2210
+ disabled,
2211
+ className,
2212
+ trigger: /* @__PURE__ */ jsxs28("span", { className: cn("ph-filter-menu-trigger", selected && "ph-filter-menu-trigger--active"), children: [
2213
+ /* @__PURE__ */ jsx31(IconTuning, { className: "h-3.5 w-3.5", "aria-hidden": true }),
2214
+ /* @__PURE__ */ jsx31("span", { className: "ph-filter-menu-trigger__label", children: label }),
2215
+ /* @__PURE__ */ jsx31("span", { className: "ph-filter-menu-trigger__value", children: displayValue })
2216
+ ] }),
2217
+ children: /* @__PURE__ */ jsx31(DropdownRadioGroup, { value, onValueChange, children: options.map((option) => /* @__PURE__ */ jsx31(
2218
+ DropdownRadioItem,
2219
+ {
2220
+ value: option.value,
2221
+ textValue: getOptionText(option),
2222
+ disabled: option.disabled,
2223
+ children: option.label
2224
+ },
2225
+ option.value
2226
+ )) })
2227
+ }
2228
+ );
2229
+ }
2230
+ function SortMenu({
2231
+ label,
2232
+ value,
2233
+ options,
2234
+ onValueChange,
2235
+ direction = "descending",
2236
+ align = "end",
2237
+ disabled,
2238
+ className
2239
+ }) {
2240
+ const selected = options.find((option) => option.value === value);
2241
+ return /* @__PURE__ */ jsx31(
2242
+ DropdownMenu,
2243
+ {
2244
+ "aria-label": `${label}: ${selected ? getOptionText(selected) : "Choose sort order"}`,
2245
+ align,
2246
+ disabled,
2247
+ className,
2248
+ trigger: /* @__PURE__ */ jsxs28("span", { className: "ph-filter-menu-trigger ph-sort-menu-trigger", children: [
2249
+ /* @__PURE__ */ jsx31(
2250
+ IconArrowDown,
2251
+ {
2252
+ className: cn("h-3.5 w-3.5", direction === "ascending" && "rotate-180"),
2253
+ "aria-hidden": true
2254
+ }
2255
+ ),
2256
+ /* @__PURE__ */ jsx31("span", { className: "ph-filter-menu-trigger__label", children: label }),
2257
+ selected ? /* @__PURE__ */ jsx31("span", { className: "ph-filter-menu-trigger__value", children: selected.label }) : null
2258
+ ] }),
2259
+ children: /* @__PURE__ */ jsx31(DropdownRadioGroup, { value, onValueChange, children: options.map((option) => /* @__PURE__ */ jsx31(
2260
+ DropdownRadioItem,
2261
+ {
2262
+ value: option.value,
2263
+ textValue: getOptionText(option),
2264
+ disabled: option.disabled,
2265
+ children: option.label
2266
+ },
2267
+ option.value
2268
+ )) })
2269
+ }
2270
+ );
2271
+ }
2272
+ function getOptionText(option) {
2273
+ if (option.textValue) return option.textValue;
2274
+ if (typeof option.label === "string" || typeof option.label === "number") return String(option.label);
2275
+ return option.value;
2276
+ }
2277
+
2278
+ // src/components/ui/FilterControls.tsx
2279
+ import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
2280
+ function FilterControls(_a) {
2281
+ var _b = _a, {
2282
+ children,
2283
+ barProps,
2284
+ chipsProps,
2285
+ emptyState,
2286
+ className
2287
+ } = _b, props = __objRest(_b, [
2288
+ "children",
2289
+ "barProps",
2290
+ "chipsProps",
2291
+ "emptyState",
2292
+ "className"
2293
+ ]);
2294
+ const hasChips = Boolean(chipsProps == null ? void 0 : chipsProps.chips.length);
2295
+ return /* @__PURE__ */ jsxs29("div", __spreadProps(__spreadValues({ className: cn("ph-filter-controls", className) }, props), { children: [
2296
+ /* @__PURE__ */ jsx32(FilterBar, __spreadProps(__spreadValues({}, barProps), { children })),
2297
+ hasChips && chipsProps ? /* @__PURE__ */ jsx32(FilterChips, __spreadValues({}, chipsProps)) : emptyState != null ? emptyState : null
2298
+ ] }));
2299
+ }
2300
+
2301
+ // src/components/ui/CodeBlock.tsx
2302
+ import { useState as useState6 } from "react";
2303
+ import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2304
+ function CodeBlock({ code, language = "tsx", filename, className }) {
2305
+ const [copied, setCopied] = useState6(false);
2306
+ const handleCopy = async () => {
2307
+ await navigator.clipboard.writeText(code);
2308
+ setCopied(true);
2309
+ setTimeout(() => setCopied(false), 2e3);
2310
+ };
2311
+ return /* @__PURE__ */ jsxs30("div", { className: cn("overflow-hidden rounded-lg border border-ph-border bg-[#1a1a2e]", className), children: [
2312
+ (filename || language) && /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between border-b border-white/10 px-4 py-2", children: [
2313
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
2314
+ /* @__PURE__ */ jsxs30("div", { className: "flex gap-1.5", children: [
2315
+ /* @__PURE__ */ jsx33("div", { className: "h-3 w-3 rounded-full bg-red-400" }),
2316
+ /* @__PURE__ */ jsx33("div", { className: "h-3 w-3 rounded-full bg-amber-400" }),
2317
+ /* @__PURE__ */ jsx33("div", { className: "h-3 w-3 rounded-full bg-emerald-400" })
2318
+ ] }),
2319
+ filename && /* @__PURE__ */ jsx33("span", { className: "ml-2 text-xs text-white/60", children: filename })
2320
+ ] }),
2321
+ /* @__PURE__ */ jsx33(
2322
+ "button",
2323
+ {
2324
+ type: "button",
2325
+ onClick: handleCopy,
2326
+ className: "text-xs text-white/60 transition hover:text-white",
2327
+ children: copied ? "Copied!" : "Copy"
2328
+ }
2329
+ )
2330
+ ] }),
2331
+ /* @__PURE__ */ jsx33("pre", { className: "overflow-x-auto p-4 text-sm leading-relaxed", children: /* @__PURE__ */ jsx33("code", { className: "font-mono text-[#e4e4e7]", children: code }) })
2332
+ ] });
2333
+ }
2334
+
2335
+ // src/components/ui/ComponentDocs.tsx
2336
+ import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
2337
+ function ComponentDocs({ title = "Props & variants", rows, defaultOpen = false, className }) {
2338
+ return /* @__PURE__ */ jsxs31("details", { className: cn("ph-panel group overflow-hidden p-0", className), open: defaultOpen, children: [
2339
+ /* @__PURE__ */ jsxs31("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: [
2340
+ /* @__PURE__ */ jsx34("h3", { className: "text-xs font-semibold uppercase tracking-wider text-ph-mutedtext", children: title }),
2341
+ /* @__PURE__ */ jsxs31("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: [
2342
+ /* @__PURE__ */ jsx34("span", { className: "group-open:hidden", children: "Show" }),
2343
+ /* @__PURE__ */ jsx34("span", { className: "hidden group-open:inline", children: "Hide" })
2344
+ ] })
2345
+ ] }),
2346
+ /* @__PURE__ */ jsx34("div", { className: "overflow-x-auto border-t border-ph-border", children: /* @__PURE__ */ jsxs31("table", { className: "w-full text-left text-sm", children: [
2347
+ /* @__PURE__ */ jsx34("thead", { className: "bg-ph-muted text-xs uppercase tracking-wider text-ph-mutedtext", children: /* @__PURE__ */ jsxs31("tr", { children: [
2348
+ /* @__PURE__ */ jsx34("th", { className: "px-4 py-2 font-semibold", children: "Prop" }),
2349
+ /* @__PURE__ */ jsx34("th", { className: "px-4 py-2 font-semibold", children: "Type" }),
2350
+ /* @__PURE__ */ jsx34("th", { className: "px-4 py-2 font-semibold", children: "Default" }),
2351
+ /* @__PURE__ */ jsx34("th", { className: "px-4 py-2 font-semibold", children: "Use" })
2352
+ ] }) }),
2353
+ /* @__PURE__ */ jsx34("tbody", { className: "divide-y divide-ph-border", children: rows.map((row) => {
2354
+ var _a, _b;
2355
+ return /* @__PURE__ */ jsxs31("tr", { children: [
2356
+ /* @__PURE__ */ jsx34("td", { className: "px-4 py-3 align-top font-mono text-xs text-ph-ink", children: row.name }),
2357
+ /* @__PURE__ */ jsx34("td", { className: "px-4 py-3 align-top font-mono text-xs text-ph-subtle", children: row.type }),
2358
+ /* @__PURE__ */ jsx34("td", { className: "px-4 py-3 align-top font-mono text-xs text-ph-subtle", children: (_a = row.defaultValue) != null ? _a : "-" }),
2359
+ /* @__PURE__ */ jsx34("td", { className: "px-4 py-3 align-top text-ph-subtle", children: (_b = row.description) != null ? _b : /* @__PURE__ */ jsx34("span", { className: "text-ph-mutedtext", children: "\u2014" }) })
2360
+ ] }, row.name);
2361
+ }) })
2362
+ ] }) })
2363
+ ] });
2364
+ }
2365
+
2366
+ // src/components/ui/ShowcaseWrapper.tsx
2367
+ import { useState as useState7 } from "react";
2368
+ import { jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
2369
+ function ShowcaseWrapper({
2370
+ id,
2371
+ title,
2372
+ description,
2373
+ docs,
2374
+ code,
2375
+ filename = "Example.tsx",
2376
+ children,
2377
+ className
2378
+ }) {
2379
+ var _a;
2380
+ const [showCode, setShowCode] = useState7(false);
2381
+ const fallbackId = (_a = titleIdMap[title]) != null ? _a : title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2382
+ return /* @__PURE__ */ jsxs32("section", { id: id != null ? id : fallbackId, className: cn("scroll-mt-20", className), children: [
2383
+ /* @__PURE__ */ jsxs32("div", { className: "ph-h2-rule mb-8", children: [
2384
+ /* @__PURE__ */ jsxs32("div", { className: "flex items-center gap-1.5", children: [
2385
+ /* @__PURE__ */ jsx35("h2", { children: title }),
2386
+ /* @__PURE__ */ jsx35(
2387
+ "button",
2388
+ {
2389
+ type: "button",
2390
+ onClick: () => setShowCode(!showCode),
2391
+ className: cn(
2392
+ "flex h-10 w-10 items-center justify-center rounded-full border transition-all",
2393
+ 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"
2394
+ ),
2395
+ title: showCode ? "Hide code" : "Show code",
2396
+ "aria-label": showCode ? "Hide code" : "Show code",
2397
+ children: /* @__PURE__ */ jsx35(IconCodePreview, { className: "h-5 w-5", "aria-hidden": true })
2398
+ }
2399
+ )
2400
+ ] }),
2401
+ /* @__PURE__ */ jsx35("hr", {})
2402
+ ] }),
2403
+ description && /* @__PURE__ */ jsx35("p", { className: "mb-6 text-sm text-ph-subtle", children: description }),
2404
+ docs && /* @__PURE__ */ jsx35("div", { className: "mb-6", children: docs }),
2405
+ /* @__PURE__ */ jsxs32(
2406
+ "div",
2407
+ {
2408
+ className: cn(
2409
+ "gap-6",
2410
+ showCode ? "lg:grid lg:grid-cols-[1fr,minmax(360px,420px)]" : "block"
2411
+ ),
2412
+ children: [
2413
+ /* @__PURE__ */ jsx35("div", { className: cn("min-w-0", showCode && "lg:pr-2"), children }),
2414
+ /* @__PURE__ */ jsx35(
2415
+ "div",
2416
+ {
2417
+ className: cn(
2418
+ "transition-all duration-300",
2419
+ showCode ? "block opacity-100" : "hidden opacity-0 lg:hidden"
2420
+ ),
2421
+ children: /* @__PURE__ */ jsx35("div", { className: "sticky top-20", children: /* @__PURE__ */ jsx35(CodeBlock, { code, filename }) })
2422
+ }
2423
+ )
2424
+ ]
2425
+ }
2426
+ )
2427
+ ] });
2428
+ }
2429
+ var titleIdMap = {
2430
+ "Icons": "icons",
2431
+ "Colour tokens": "colors",
2432
+ "Buttons": "buttons",
2433
+ "Badges": "badges",
2434
+ "Alerts": "alerts",
2435
+ "Toasts": "toasts",
2436
+ "Cards": "cards",
2437
+ "Forms": "forms",
2438
+ "Inputs & Forms": "forms",
2439
+ "Tables": "tables",
2440
+ "Accordion": "accordion",
2441
+ "Calendar": "calendar",
2442
+ "Hover Card": "hovercard",
2443
+ "Modals": "modals",
2444
+ "Drawers": "drawers",
2445
+ "Navigation chrome": "navigation",
2446
+ "Navigation utilities": "utilities",
2447
+ "Stepper": "stepper",
2448
+ "Command Palette": "command",
2449
+ "Filter Chips": "filters",
2450
+ "Empty State": "emptystate",
2451
+ "Charts (PostHog-style)": "charts",
2452
+ "Dashboard shells": "dashboard",
2453
+ "Tabs": "tabs",
2454
+ "Dropdowns": "dropdowns",
2455
+ "Progress & loading": "progress",
2456
+ "Tooltip": "tooltip",
2457
+ "Avatars": "avatars",
2458
+ "Stats & conversational UI": "stats",
2459
+ "Timeline": "timeline",
2460
+ "Countdown motif": "countdown",
2461
+ "Keyboard glyphs": "kbd",
2462
+ "Icon swap": "swap",
2463
+ "Stacked surfaces": "stack",
2464
+ "Diff slider": "diff",
2465
+ "Badge hotspots": "indicator",
2466
+ "Terminal capture": "code-mockup"
2467
+ };
2468
+
2469
+ // src/components/ui/CollapsibleSection.tsx
2470
+ import { useId as useId5, useState as useState8 } from "react";
2471
+ import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
2472
+ function CollapsibleSection({ title, children, defaultOpen = true, id }) {
2473
+ const [isOpen, setIsOpen] = useState8(defaultOpen);
2474
+ const generatedId = useId5();
2475
+ const contentId = `${id != null ? id : generatedId}-content`;
2476
+ return /* @__PURE__ */ jsxs33("section", { id, className: "scroll-mt-20", children: [
2477
+ /* @__PURE__ */ jsxs33(
2478
+ "button",
2479
+ {
2480
+ type: "button",
2481
+ onClick: () => setIsOpen(!isOpen),
2482
+ "aria-expanded": isOpen,
2483
+ "aria-controls": contentId,
2484
+ 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",
2485
+ children: [
2486
+ /* @__PURE__ */ jsx36("span", { className: "text-lg font-bold text-ph-ink", children: title }),
2487
+ /* @__PURE__ */ jsx36(
2488
+ IconChevronDown,
2489
+ {
2490
+ className: cn(
2491
+ "h-5 w-5 text-ph-subtle transition-transform duration-200",
2492
+ isOpen && "rotate-180"
2493
+ ),
2494
+ "aria-hidden": true
2495
+ }
2496
+ )
2497
+ ]
2498
+ }
2499
+ ),
2500
+ /* @__PURE__ */ jsx36(
2501
+ "div",
2502
+ {
2503
+ id: contentId,
2504
+ "aria-hidden": !isOpen,
2505
+ className: cn(
2506
+ "overflow-hidden transition-all duration-300",
2507
+ isOpen ? "max-h-[50000px] opacity-100" : "max-h-0 opacity-0"
2508
+ ),
2509
+ children
2510
+ }
2511
+ )
2512
+ ] });
2513
+ }
2514
+
2515
+ // src/components/ui/Typography.tsx
2516
+ import { jsx as jsx37 } from "react/jsx-runtime";
2517
+ var toneMap2 = {
2518
+ default: "text-ph-ink",
2519
+ muted: "text-ph-mutedtext",
2520
+ subtle: "text-ph-subtle",
2521
+ brand: "text-ph-brand",
2522
+ danger: "text-ph-danger",
2523
+ success: "text-ph-success",
2524
+ warning: "text-ph-warning",
2525
+ info: "text-ph-info",
2526
+ inherit: ""
2527
+ };
2528
+ var weightMap = {
2529
+ normal: "font-normal",
2530
+ medium: "font-medium",
2531
+ semibold: "font-semibold",
2532
+ bold: "font-bold",
2533
+ extrabold: "font-extrabold"
2534
+ };
2535
+ function textClass(base, tone, weight, truncate, className) {
2536
+ return cn(base, toneMap2[tone], weight && weightMap[weight], truncate && "truncate", className);
2537
+ }
2538
+ function Display({
2539
+ children,
2540
+ tone = "default",
2541
+ weight,
2542
+ truncate,
2543
+ className
2544
+ }) {
2545
+ return /* @__PURE__ */ jsx37("h1", { className: textClass("text-4xl font-extrabold tracking-tight md:text-5xl", tone, weight, truncate, className), children });
2546
+ }
2547
+ function H1({ children, tone = "default", weight, truncate, className }) {
2548
+ return /* @__PURE__ */ jsx37("h1", { className: textClass("text-3xl font-bold tracking-tight md:text-4xl", tone, weight, truncate, className), children });
2549
+ }
2550
+ function H2({ children, tone = "default", weight, truncate, className }) {
2551
+ return /* @__PURE__ */ jsx37("h2", { className: textClass("text-2xl font-bold tracking-tight", tone, weight, truncate, className), children });
2552
+ }
2553
+ function H3({ children, tone = "default", weight, truncate, className }) {
2554
+ return /* @__PURE__ */ jsx37("h3", { className: textClass("text-xl font-semibold", tone, weight, truncate, className), children });
2555
+ }
2556
+ function H4({ children, tone = "default", weight, truncate, className }) {
2557
+ return /* @__PURE__ */ jsx37("h4", { className: textClass("text-lg font-semibold", tone, weight, truncate, className), children });
2558
+ }
2559
+ function H5({ children, tone = "default", weight, truncate, className }) {
2560
+ return /* @__PURE__ */ jsx37("h5", { className: textClass("text-base font-semibold", tone, weight, truncate, className), children });
2561
+ }
2562
+ function P({ children, tone = "default", weight, truncate, className }) {
2563
+ return /* @__PURE__ */ jsx37("p", { className: textClass("text-base leading-relaxed", tone, weight, truncate, className), children });
2564
+ }
2565
+ function Small({ children, tone = "default", weight, truncate, className }) {
2566
+ return /* @__PURE__ */ jsx37("span", { className: textClass("text-sm leading-relaxed", tone, weight, truncate, className), children });
2567
+ }
2568
+ function Caption({ children, tone = "muted", weight, truncate, className }) {
2569
+ return /* @__PURE__ */ jsx37("span", { className: textClass("text-[11px] font-medium uppercase tracking-wider", tone, weight, truncate, className), children });
2570
+ }
2571
+ function Overline({ children, tone = "muted", weight, truncate, className }) {
2572
+ return /* @__PURE__ */ jsx37("span", { className: textClass("text-[10px] font-bold uppercase tracking-[0.15em]", tone, weight, truncate, className), children });
2573
+ }
2574
+ function Lead({ children, tone = "subtle", weight, truncate, className }) {
2575
+ return /* @__PURE__ */ jsx37("p", { className: textClass("text-lg leading-relaxed", tone, weight, truncate, className), children });
2576
+ }
2577
+ function Mono({ children, tone = "default", weight, truncate, className }) {
2578
+ return /* @__PURE__ */ jsx37("code", { className: textClass("text-sm font-mono leading-relaxed", tone, weight, truncate, className), children });
2579
+ }
2580
+ function Label({ children, tone = "default", weight, truncate, className }) {
2581
+ return /* @__PURE__ */ jsx37("label", { className: textClass("text-sm font-medium", tone, weight, truncate, className), children });
2582
+ }
2583
+
2584
+ // src/components/ui/Avatar.tsx
2585
+ import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
2586
+ var sizeMap5 = {
2587
+ xs: "h-8 w-8 text-[10px]",
2588
+ sm: "h-10 w-10 text-xs",
2589
+ md: "h-12 w-12 text-base",
2590
+ lg: "h-16 w-16 text-xl",
2591
+ xl: "h-24 w-24 text-3xl"
2592
+ };
2593
+ var statusMap = {
2594
+ online: "bg-emerald-500",
2595
+ offline: "bg-ph-mutedtext",
2596
+ away: "bg-amber-400",
2597
+ busy: "bg-ph-danger"
2598
+ };
2599
+ function Avatar(_a) {
2600
+ var _b = _a, {
2601
+ label,
2602
+ icon,
2603
+ size = "md",
2604
+ color = "bg-ph-brand text-white",
2605
+ status,
2606
+ badge,
2607
+ className
2608
+ } = _b, props = __objRest(_b, [
2609
+ "label",
2610
+ "icon",
2611
+ "size",
2612
+ "color",
2613
+ "status",
2614
+ "badge",
2615
+ "className"
2616
+ ]);
2617
+ return /* @__PURE__ */ jsxs34("div", __spreadProps(__spreadValues({ className: cn("relative inline-flex shrink-0", className) }, props), { children: [
2618
+ /* @__PURE__ */ jsx38(
2619
+ "div",
2620
+ {
2621
+ className: cn(
2622
+ "flex items-center justify-center rounded-full border border-ph-border font-bold shadow-ph",
2623
+ sizeMap5[size],
2624
+ color
2625
+ ),
2626
+ children: icon || label
2627
+ }
2628
+ ),
2629
+ status && /* @__PURE__ */ jsx38(
2630
+ "span",
2631
+ {
2632
+ className: cn(
2633
+ "absolute bottom-0 right-1 h-2.5 w-2.5 rounded-full border-2 border-white",
2634
+ statusMap[status]
2635
+ )
2636
+ }
2637
+ ),
2638
+ badge && /* @__PURE__ */ jsx38("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 })
2639
+ ] }));
2640
+ }
2641
+ function AvatarGroup(_a) {
2642
+ var _b = _a, { children, max, className } = _b, props = __objRest(_b, ["children", "max", "className"]);
2643
+ const items = Array.isArray(children) ? children : [children];
2644
+ const visible = max ? items.slice(0, max) : items;
2645
+ const remaining = max ? items.length - max : 0;
2646
+ return /* @__PURE__ */ jsxs34("div", __spreadProps(__spreadValues({ className: cn("-space-x-3 flex rtl:space-x-reverse", className) }, props), { children: [
2647
+ visible,
2648
+ remaining > 0 && /* @__PURE__ */ jsx38(
2649
+ Avatar,
2650
+ {
2651
+ label: `+${remaining}`,
2652
+ size: "md",
2653
+ color: "bg-ph-toolbar text-ph-subtle"
2654
+ }
2655
+ )
2656
+ ] }));
2657
+ }
2658
+
2659
+ // src/components/ui/Progress.tsx
2660
+ import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
2661
+ var sizeMap6 = {
2662
+ sm: "h-1",
2663
+ md: "h-2",
2664
+ lg: "h-3"
2665
+ };
2666
+ function Progress(_a) {
2667
+ var _b = _a, {
2668
+ value,
2669
+ max = 100,
2670
+ color = "bg-ph-brand",
2671
+ label,
2672
+ showPercentage = false,
2673
+ size = "md",
2674
+ className
2675
+ } = _b, props = __objRest(_b, [
2676
+ "value",
2677
+ "max",
2678
+ "color",
2679
+ "label",
2680
+ "showPercentage",
2681
+ "size",
2682
+ "className"
2683
+ ]);
2684
+ const percentage = Math.min(100, Math.max(0, value / max * 100));
2685
+ return /* @__PURE__ */ jsxs35("div", __spreadProps(__spreadValues({ className: cn("w-full", className) }, props), { children: [
2686
+ (label || showPercentage) && /* @__PURE__ */ jsxs35("div", { className: "mb-1.5 flex justify-between text-sm text-ph-subtle", children: [
2687
+ label && /* @__PURE__ */ jsx39("span", { children: label }),
2688
+ showPercentage && /* @__PURE__ */ jsxs35("span", { className: "tabular-nums", children: [
2689
+ Math.round(percentage),
2690
+ "%"
2691
+ ] })
2692
+ ] }),
2693
+ /* @__PURE__ */ jsx39("div", { className: cn("ph-progress", sizeMap6[size]), children: /* @__PURE__ */ jsx39(
2694
+ "div",
2695
+ {
2696
+ className: cn("ph-progress-bar", color),
2697
+ style: { width: `${percentage}%` },
2698
+ role: "progressbar",
2699
+ "aria-valuenow": value,
2700
+ "aria-valuemin": 0,
2701
+ "aria-valuemax": max
2702
+ }
2703
+ ) })
2704
+ ] }));
2705
+ }
2706
+
2707
+ // src/components/ui/ChatBubble.tsx
2708
+ import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
2709
+ function ChatBubble(_a) {
2710
+ var _b = _a, {
2711
+ children,
2712
+ avatar,
2713
+ name,
2714
+ time,
2715
+ variant = "from",
2716
+ footer,
2717
+ className
2718
+ } = _b, props = __objRest(_b, [
2719
+ "children",
2720
+ "avatar",
2721
+ "name",
2722
+ "time",
2723
+ "variant",
2724
+ "footer",
2725
+ "className"
2726
+ ]);
2727
+ const isSelf = variant === "self";
2728
+ return /* @__PURE__ */ jsxs36(
2729
+ "div",
2730
+ __spreadProps(__spreadValues({
2731
+ className: cn(
2732
+ "flex gap-3",
2733
+ isSelf && "flex-row-reverse",
2734
+ className
2735
+ )
2736
+ }, props), {
2737
+ children: [
2738
+ avatar && /* @__PURE__ */ jsx40("div", { className: "shrink-0", children: avatar }),
2739
+ /* @__PURE__ */ jsxs36("div", { className: cn("min-w-0 flex-1", isSelf && "text-right"), children: [
2740
+ (name || time) && /* @__PURE__ */ jsxs36(
2741
+ "header",
2742
+ {
2743
+ className: cn(
2744
+ "flex gap-2 text-xs text-ph-mutedtext",
2745
+ isSelf && "flex-row-reverse justify-end"
2746
+ ),
2747
+ children: [
2748
+ name && /* @__PURE__ */ jsx40("span", { className: "font-semibold text-ph-ink", children: name }),
2749
+ time && /* @__PURE__ */ jsx40("span", { children: time })
2750
+ ]
2751
+ }
2752
+ ),
2753
+ /* @__PURE__ */ jsx40(
2754
+ "div",
2755
+ {
2756
+ className: cn(
2757
+ "mt-2 inline-block text-left shadow-ph",
2758
+ isSelf ? "ph-chat-self" : "ph-chat-from"
2759
+ ),
2760
+ children
2761
+ }
2762
+ ),
2763
+ footer && /* @__PURE__ */ jsx40("footer", { className: "mt-2 text-[11px] text-ph-mutedtext", children: footer })
2764
+ ] })
2765
+ ]
2766
+ })
2767
+ );
2768
+ }
2769
+
2770
+ // src/components/ui/Terminal.tsx
2771
+ import { Fragment as Fragment5, jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
2772
+ function Terminal(_a) {
2773
+ var _b = _a, {
2774
+ title = "sandbox",
2775
+ lines,
2776
+ children,
2777
+ className
2778
+ } = _b, props = __objRest(_b, [
2779
+ "title",
2780
+ "lines",
2781
+ "children",
2782
+ "className"
2783
+ ]);
2784
+ return /* @__PURE__ */ jsxs37(
2785
+ "div",
2786
+ __spreadProps(__spreadValues({
2787
+ className: cn(
2788
+ "overflow-hidden rounded-xl border border-ph-border shadow-ph-md",
2789
+ className
2790
+ )
2791
+ }, props), {
2792
+ children: [
2793
+ /* @__PURE__ */ jsxs37("header", { className: "flex items-center gap-2 border-b border-ph-border bg-ph-muted px-4 py-3", children: [
2794
+ /* @__PURE__ */ jsx41("div", { className: "h-3 w-3 rounded-full bg-red-400" }),
2795
+ /* @__PURE__ */ jsx41("div", { className: "h-3 w-3 rounded-full bg-amber-400" }),
2796
+ /* @__PURE__ */ jsx41("div", { className: "h-3 w-3 rounded-full bg-emerald-400" }),
2797
+ title && /* @__PURE__ */ jsx41("span", { className: "text-xs font-medium text-ph-mutedtext", children: title })
2798
+ ] }),
2799
+ /* @__PURE__ */ jsx41("div", { className: "ph-code rounded-none border-x-0 border-b-0 text-[13px] leading-relaxed", children: children || /* @__PURE__ */ jsx41(Fragment5, { children: lines == null ? void 0 : lines.map((line, i) => {
2800
+ const text = typeof line === "string" ? line : line.text;
2801
+ const color = typeof line === "string" ? void 0 : line.color;
2802
+ return /* @__PURE__ */ jsxs37("span", { children: [
2803
+ /* @__PURE__ */ jsx41("span", { className: color || "text-neutral-600", children: text }),
2804
+ i < lines.length - 1 && /* @__PURE__ */ jsx41("br", {})
2805
+ ] }, i);
2806
+ }) }) })
2807
+ ]
2808
+ })
2809
+ );
2810
+ }
2811
+
2812
+ // src/components/ui/Indicator.tsx
2813
+ import { jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
2814
+ var positionMap = {
2815
+ "top-right": "-right-[2px] -top-[2px]",
2816
+ "top-left": "-left-[2px] -top-[2px]",
2817
+ "bottom-right": "-right-[2px] -bottom-[2px]",
2818
+ "bottom-left": "-left-[2px] -bottom-[2px]"
2819
+ };
2820
+ function Indicator(_a) {
2821
+ var _b = _a, {
2822
+ children,
2823
+ badge,
2824
+ color = "bg-ph-brand",
2825
+ position = "top-right",
2826
+ dot = false,
2827
+ className
2828
+ } = _b, props = __objRest(_b, [
2829
+ "children",
2830
+ "badge",
2831
+ "color",
2832
+ "position",
2833
+ "dot",
2834
+ "className"
2835
+ ]);
2836
+ return /* @__PURE__ */ jsxs38("div", __spreadProps(__spreadValues({ className: cn("relative inline-flex items-center justify-center", className) }, props), { children: [
2837
+ dot ? /* @__PURE__ */ jsx42(
2838
+ "span",
2839
+ {
2840
+ className: cn(
2841
+ "absolute z-10 h-2.5 w-2.5 rounded-full border-2 border-white",
2842
+ color,
2843
+ positionMap[position]
2844
+ )
2845
+ }
2846
+ ) : badge != null ? /* @__PURE__ */ jsx42(
2847
+ "span",
2848
+ {
2849
+ className: cn(
2850
+ "absolute z-10 flex min-h-[22px] min-w-[22px] items-center justify-center rounded-full px-1 text-[11px] font-bold text-white",
2851
+ color,
2852
+ positionMap[position]
2853
+ ),
2854
+ children: badge
2855
+ }
2856
+ ) : null,
2857
+ children
2858
+ ] }));
2859
+ }
2860
+
2861
+ // src/components/ui/Timeline.tsx
2862
+ import { jsx as jsx43, jsxs as jsxs39 } from "react/jsx-runtime";
2863
+ function Timeline(_a) {
2864
+ var _b = _a, {
2865
+ events,
2866
+ alternate = false,
2867
+ className
2868
+ } = _b, props = __objRest(_b, [
2869
+ "events",
2870
+ "alternate",
2871
+ "className"
2872
+ ]);
2873
+ return /* @__PURE__ */ jsx43(
2874
+ "ol",
2875
+ __spreadProps(__spreadValues({
2876
+ className: cn("relative space-y-8", className)
2877
+ }, props), {
2878
+ children: events.map((event, idx) => {
2879
+ const align = alternate && idx % 2 !== 0 ? "lg:flex-row-reverse" : "";
2880
+ return /* @__PURE__ */ jsxs39("li", { className: cn("relative flex gap-6", align), children: [
2881
+ /* @__PURE__ */ jsx43(
2882
+ "div",
2883
+ {
2884
+ className: cn(
2885
+ "relative z-10 flex h-12 w-12 shrink-0 items-center justify-center rounded-full ring-8 ring-ph-muted shadow-md",
2886
+ event.color || "bg-ph-brand text-white"
2887
+ ),
2888
+ children: event.icon
2889
+ }
2890
+ ),
2891
+ /* @__PURE__ */ jsxs39("article", { className: "flex-1 rounded-xl border border-ph-border bg-ph-surface p-4 shadow-ph", children: [
2892
+ /* @__PURE__ */ jsxs39("div", { className: "flex flex-wrap items-baseline gap-3", children: [
2893
+ /* @__PURE__ */ jsx43("h4", { className: "text-base font-semibold text-ph-ink", children: event.title }),
2894
+ event.time && /* @__PURE__ */ jsx43("time", { className: "text-[11px] font-semibold uppercase tracking-wide text-ph-mutedtext", children: event.time })
2895
+ ] }),
2896
+ event.description && /* @__PURE__ */ jsx43("p", { className: "mt-2 text-sm text-ph-subtle", children: event.description })
2897
+ ] })
2898
+ ] }, event.id);
2899
+ })
2900
+ })
2901
+ );
2902
+ }
2903
+
2904
+ // src/components/ui/Banner.tsx
2905
+ import { forwardRef as forwardRef6 } from "react";
2906
+ import { jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
2907
+ var typeClass = {
2908
+ info: "ph-banner-info",
2909
+ success: "ph-banner-success",
2910
+ warning: "ph-banner-warning",
2911
+ danger: "ph-banner-danger",
2912
+ ai: "ph-banner-ai"
2913
+ };
2914
+ var Banner = forwardRef6(function Banner2(_a, ref) {
2915
+ var _b = _a, {
2916
+ type = "info",
2917
+ onClose,
2918
+ action,
2919
+ hideIcon = false,
2920
+ square = false,
2921
+ icon,
2922
+ className,
2923
+ children
2924
+ } = _b, props = __objRest(_b, [
2925
+ "type",
2926
+ "onClose",
2927
+ "action",
2928
+ "hideIcon",
2929
+ "square",
2930
+ "icon",
2931
+ "className",
2932
+ "children"
2933
+ ]);
2934
+ return /* @__PURE__ */ jsx44(
2935
+ "div",
2936
+ __spreadProps(__spreadValues({
2937
+ ref,
2938
+ role: "alert",
2939
+ className: cn(
2940
+ "ph-banner",
2941
+ typeClass[type],
2942
+ square && "ph-banner--square",
2943
+ className
2944
+ )
2945
+ }, props), {
2946
+ children: /* @__PURE__ */ jsxs40("div", { className: "ph-banner__body", children: [
2947
+ icon,
2948
+ /* @__PURE__ */ jsx44("div", { className: "ph-banner__content", children }),
2949
+ action && /* @__PURE__ */ jsx44("div", { className: "ph-banner__action", children: action }),
2950
+ onClose && /* @__PURE__ */ jsx44("button", { type: "button", onClick: onClose, className: "ph-banner__close", "aria-label": "Dismiss", children: /* @__PURE__ */ jsx44("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx44("path", { d: "M4 4l8 8M12 4l-8 8" }) }) })
2951
+ ] })
2952
+ })
2953
+ );
2954
+ });
2955
+ Banner.displayName = "Banner";
2956
+
2957
+ // src/components/ui/Dialog.tsx
2958
+ import { useState as useState9 } from "react";
2959
+ import { jsx as jsx45, jsxs as jsxs41 } from "react/jsx-runtime";
2960
+ function Dialog2(_a) {
2961
+ var _b = _a, {
2962
+ isOpen: openProp,
2963
+ onClose,
2964
+ onConfirm,
2965
+ confirmText = "Confirm",
2966
+ cancelText = "Cancel",
2967
+ confirmProps,
2968
+ cancelProps,
2969
+ children,
2970
+ title
2971
+ } = _b, modalProps = __objRest(_b, [
2972
+ "isOpen",
2973
+ "onClose",
2974
+ "onConfirm",
2975
+ "confirmText",
2976
+ "cancelText",
2977
+ "confirmProps",
2978
+ "cancelProps",
2979
+ "children",
2980
+ "title"
2981
+ ]);
2982
+ const [loading, setLoading] = useState9(false);
2983
+ const isOpen = openProp != null ? openProp : true;
2984
+ const handleConfirm = async () => {
2985
+ if (!onConfirm) return;
2986
+ setLoading(true);
2987
+ try {
2988
+ await onConfirm();
2989
+ } finally {
2990
+ setLoading(false);
2991
+ }
2992
+ onClose == null ? void 0 : onClose();
2993
+ };
2994
+ return /* @__PURE__ */ jsx45(
2995
+ Modal,
2996
+ __spreadProps(__spreadValues({
2997
+ open: isOpen,
2998
+ onClose,
2999
+ title,
3000
+ footer: /* @__PURE__ */ jsxs41("div", { className: "flex justify-end gap-2", children: [
3001
+ /* @__PURE__ */ jsx45(Button, __spreadProps(__spreadValues({ variant: "secondary" }, cancelProps), { onClick: onClose, children: cancelText })),
3002
+ onConfirm && /* @__PURE__ */ jsx45(
3003
+ Button,
3004
+ __spreadProps(__spreadValues({
3005
+ variant: "primary",
3006
+ loading
3007
+ }, confirmProps), {
3008
+ onClick: handleConfirm,
3009
+ children: confirmText
3010
+ })
3011
+ )
3012
+ ] })
3013
+ }, modalProps), {
3014
+ children
3015
+ })
3016
+ );
3017
+ }
3018
+ Dialog2.displayName = "Dialog";
3019
+
3020
+ // src/components/ui/Divider.tsx
3021
+ import { jsx as jsx46 } from "react/jsx-runtime";
3022
+ function Divider(_a) {
3023
+ var _b = _a, {
3024
+ vertical = false,
3025
+ dashed = false,
3026
+ thick = false,
3027
+ label,
3028
+ className
3029
+ } = _b, props = __objRest(_b, [
3030
+ "vertical",
3031
+ "dashed",
3032
+ "thick",
3033
+ "label",
3034
+ "className"
3035
+ ]);
3036
+ return /* @__PURE__ */ jsx46(
3037
+ "div",
3038
+ __spreadProps(__spreadValues({
3039
+ role: "separator",
3040
+ "aria-orientation": vertical ? "vertical" : "horizontal",
3041
+ className: cn(
3042
+ "ph-divider",
3043
+ vertical && "ph-divider--vertical",
3044
+ thick && "ph-divider--thick",
3045
+ dashed && "ph-divider--dashed",
3046
+ !!label && "ph-divider--with-label",
3047
+ !className && (vertical ? "mx-2 self-stretch" : "my-2"),
3048
+ className
3049
+ )
3050
+ }, props), {
3051
+ children: label && /* @__PURE__ */ jsx46("span", { className: "ph-divider__label", children: label })
3052
+ })
3053
+ );
3054
+ }
3055
+ Divider.displayName = "Divider";
3056
+
3057
+ // src/components/ui/Tag.tsx
3058
+ import { forwardRef as forwardRef7 } from "react";
3059
+ import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
3060
+ var typeClass2 = {
3061
+ default: "ph-tag-default",
3062
+ primary: "ph-tag-primary",
3063
+ success: "ph-tag-success",
3064
+ warning: "ph-tag-warning",
3065
+ danger: "ph-tag-danger",
3066
+ info: "ph-tag-info",
3067
+ muted: "ph-tag-muted",
3068
+ highlight: "ph-tag-highlight"
3069
+ };
3070
+ var Tag = forwardRef7(function Tag2(_a, ref) {
3071
+ var _b = _a, {
3072
+ type = "default",
3073
+ size = "md",
3074
+ icon,
3075
+ closable = false,
3076
+ onClose,
3077
+ className,
3078
+ children
3079
+ } = _b, props = __objRest(_b, [
3080
+ "type",
3081
+ "size",
3082
+ "icon",
3083
+ "closable",
3084
+ "onClose",
3085
+ "className",
3086
+ "children"
3087
+ ]);
3088
+ return /* @__PURE__ */ jsxs42(
3089
+ "div",
3090
+ __spreadProps(__spreadValues({
3091
+ ref,
3092
+ className: cn(
3093
+ "ph-tag",
3094
+ typeClass2[type],
3095
+ size === "sm" && "ph-tag-sm",
3096
+ className
3097
+ )
3098
+ }, props), {
3099
+ children: [
3100
+ icon && /* @__PURE__ */ jsx47("span", { className: "ph-tag__icon", children: icon }),
3101
+ /* @__PURE__ */ jsx47("span", { className: "ph-tag__text", children }),
3102
+ closable && /* @__PURE__ */ jsx47(
3103
+ "button",
3104
+ {
3105
+ type: "button",
3106
+ onClick: (e) => {
3107
+ e.stopPropagation();
3108
+ onClose == null ? void 0 : onClose();
3109
+ },
3110
+ className: "ph-tag__close",
3111
+ "aria-label": "Remove",
3112
+ children: /* @__PURE__ */ jsx47("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx47("path", { d: "M3 3l6 6M9 3l-6 6" }) })
3113
+ }
3114
+ )
3115
+ ]
3116
+ })
3117
+ );
3118
+ });
3119
+ Tag.displayName = "Tag";
3120
+
3121
+ // src/components/ui/ProgressCircle.tsx
3122
+ import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
3123
+ function ProgressCircle(_a) {
3124
+ var _b = _a, {
3125
+ progress,
3126
+ size = 40,
3127
+ strokeWidth: sw,
3128
+ children,
3129
+ className
3130
+ } = _b, props = __objRest(_b, [
3131
+ "progress",
3132
+ "size",
3133
+ "strokeWidth",
3134
+ "children",
3135
+ "className"
3136
+ ]);
3137
+ const stroke = sw != null ? sw : size * 0.08;
3138
+ const radius = (size - stroke) / 2;
3139
+ const circumference = 2 * Math.PI * radius;
3140
+ const offset = circumference - Math.min(1, Math.max(0, progress)) * circumference;
3141
+ return /* @__PURE__ */ jsxs43(
3142
+ "span",
3143
+ __spreadProps(__spreadValues({
3144
+ className: cn("ph-progress-circle", className),
3145
+ style: { width: size, height: size },
3146
+ role: "progressbar",
3147
+ "aria-valuenow": Math.round(progress * 100),
3148
+ "aria-valuemin": 0,
3149
+ "aria-valuemax": 100
3150
+ }, props), {
3151
+ children: [
3152
+ /* @__PURE__ */ jsxs43("svg", { width: size, height: size, children: [
3153
+ /* @__PURE__ */ jsx48(
3154
+ "circle",
3155
+ {
3156
+ cx: size / 2,
3157
+ cy: size / 2,
3158
+ r: radius,
3159
+ fill: "none",
3160
+ stroke: "currentColor",
3161
+ strokeWidth: stroke,
3162
+ opacity: 0.15
3163
+ }
3164
+ ),
3165
+ /* @__PURE__ */ jsx48(
3166
+ "circle",
3167
+ {
3168
+ cx: size / 2,
3169
+ cy: size / 2,
3170
+ r: radius,
3171
+ fill: "none",
3172
+ stroke: "currentColor",
3173
+ strokeWidth: stroke,
3174
+ strokeDasharray: circumference,
3175
+ strokeDashoffset: offset,
3176
+ strokeLinecap: "round",
3177
+ transform: `rotate(-90 ${size / 2} ${size / 2})`,
3178
+ className: "ph-progress-circle__bar"
3179
+ }
3180
+ )
3181
+ ] }),
3182
+ children && /* @__PURE__ */ jsx48("span", { className: "ph-progress-circle__content", children })
3183
+ ]
3184
+ })
3185
+ );
3186
+ }
3187
+ ProgressCircle.displayName = "ProgressCircle";
3188
+
3189
+ // src/components/ui/Row.tsx
3190
+ import { forwardRef as forwardRef8 } from "react";
3191
+ import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
3192
+ var Row = forwardRef8(function Row2(_a, ref) {
3193
+ var _b = _a, {
3194
+ icon,
3195
+ sideIcon,
3196
+ status = "default",
3197
+ fullWidth = false,
3198
+ center = false,
3199
+ size = "md",
3200
+ className,
3201
+ children
3202
+ } = _b, props = __objRest(_b, [
3203
+ "icon",
3204
+ "sideIcon",
3205
+ "status",
3206
+ "fullWidth",
3207
+ "center",
3208
+ "size",
3209
+ "className",
3210
+ "children"
3211
+ ]);
3212
+ const symbolic = children === null || children === void 0 || children === false;
3213
+ return /* @__PURE__ */ jsx49(
3214
+ "div",
3215
+ __spreadProps(__spreadValues({
3216
+ ref,
3217
+ className: cn(
3218
+ "ph-row",
3219
+ status !== "default" && `ph-row--${status}`,
3220
+ fullWidth && "ph-row--full-width",
3221
+ center && "ph-row--center",
3222
+ size === "sm" && "ph-row--sm",
3223
+ size === "lg" && "ph-row--lg",
3224
+ symbolic && "ph-row--symbolic",
3225
+ className
3226
+ )
3227
+ }, props), {
3228
+ children: /* @__PURE__ */ jsxs44("div", { className: "ph-row__main", children: [
3229
+ icon && /* @__PURE__ */ jsx49("span", { className: "ph-row__icon", children: icon }),
3230
+ !symbolic && /* @__PURE__ */ jsx49("div", { className: "ph-row__content", children }),
3231
+ sideIcon && /* @__PURE__ */ jsx49("span", { className: "ph-row__side-icon", children: sideIcon })
3232
+ ] })
3233
+ })
3234
+ );
3235
+ });
3236
+ Row.displayName = "Row";
3237
+
3238
+ // src/components/ui/Widget.tsx
3239
+ import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
3240
+ function Widget({ title, onClose, actions, children, className }) {
3241
+ return /* @__PURE__ */ jsxs45("div", { className: cn("ph-widget", className), children: [
3242
+ /* @__PURE__ */ jsxs45("div", { className: "ph-widget__header", children: [
3243
+ /* @__PURE__ */ jsx50("span", { className: "ph-widget__title", children: title }),
3244
+ actions,
3245
+ onClose && /* @__PURE__ */ jsx50("button", { type: "button", onClick: onClose, className: "ph-widget__close", "aria-label": "Close", children: /* @__PURE__ */ jsx50("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx50("path", { d: "M3 3l8 8M11 3l-8 8" }) }) })
3246
+ ] }),
3247
+ /* @__PURE__ */ jsx50("div", { className: "ph-widget__content", children })
3248
+ ] });
3249
+ }
3250
+ Widget.displayName = "Widget";
3251
+
3252
+ // src/components/ui/Lettermark.tsx
3253
+ import { forwardRef as forwardRef9 } from "react";
3254
+ import { jsx as jsx51 } from "react/jsx-runtime";
3255
+ var Lettermark = forwardRef9(function Lettermark2(_a, ref) {
3256
+ var _b = _a, {
3257
+ name,
3258
+ index,
3259
+ outlined = false,
3260
+ rounded = false,
3261
+ size = "md",
3262
+ className
3263
+ } = _b, props = __objRest(_b, [
3264
+ "name",
3265
+ "index",
3266
+ "outlined",
3267
+ "rounded",
3268
+ "size",
3269
+ "className"
3270
+ ]);
3271
+ const letter = name ? typeof name === "number" ? String(Math.floor(name)) : String.fromCodePoint(name.codePointAt(0)).toLocaleUpperCase() : "?";
3272
+ return /* @__PURE__ */ jsx51(
3273
+ "div",
3274
+ __spreadProps(__spreadValues({
3275
+ ref,
3276
+ className: cn(
3277
+ "ph-lettermark",
3278
+ `ph-lettermark--${size}`,
3279
+ typeof index === "number" && `ph-lettermark--v-${index % 8 + 1}`,
3280
+ outlined && "ph-lettermark--outlined",
3281
+ rounded && "ph-lettermark--rounded",
3282
+ letter === "?" && "ph-lettermark--unknown",
3283
+ className
3284
+ ),
3285
+ "aria-hidden": "true"
3286
+ }, props), {
3287
+ children: letter
3288
+ })
3289
+ );
3290
+ });
3291
+ Lettermark.displayName = "Lettermark";
3292
+
3293
+ // src/components/ui/Splotch.tsx
3294
+ import { jsx as jsx52 } from "react/jsx-runtime";
3295
+ var colorMap = {
3296
+ purple: "ph-splotch--purple",
3297
+ blue: "ph-splotch--blue",
3298
+ green: "ph-splotch--green",
3299
+ black: "ph-splotch--black",
3300
+ white: "ph-splotch--white",
3301
+ orange: "ph-splotch--orange",
3302
+ red: "ph-splotch--red",
3303
+ yellow: "ph-splotch--yellow"
3304
+ };
3305
+ function Splotch(_a) {
3306
+ var _b = _a, { color, className } = _b, props = __objRest(_b, ["color", "className"]);
3307
+ return /* @__PURE__ */ jsx52(
3308
+ "div",
3309
+ __spreadProps(__spreadValues({
3310
+ className: cn("ph-splotch", colorMap[color], className),
3311
+ "aria-hidden": "true"
3312
+ }, props), {
3313
+ children: /* @__PURE__ */ jsx52("div", { className: "ph-splotch__paint" })
3314
+ })
3315
+ );
3316
+ }
3317
+ Splotch.displayName = "Splotch";
3318
+
3319
+ // src/components/ui/Popover.tsx
3320
+ import { useState as useState10, useRef as useRef3, useEffect as useEffect3 } from "react";
3321
+ import { jsx as jsx53, jsxs as jsxs46 } from "react/jsx-runtime";
3322
+ function Popover(_a) {
3323
+ var _b = _a, {
3324
+ trigger,
3325
+ children,
3326
+ open: controlledOpen,
3327
+ onOpenChange,
3328
+ placement = "bottom",
3329
+ matchTriggerWidth = false,
3330
+ padded = true,
3331
+ className
3332
+ } = _b, props = __objRest(_b, [
3333
+ "trigger",
3334
+ "children",
3335
+ "open",
3336
+ "onOpenChange",
3337
+ "placement",
3338
+ "matchTriggerWidth",
3339
+ "padded",
3340
+ "className"
3341
+ ]);
3342
+ var _a2;
3343
+ const [internalOpen, setInternalOpen] = useState10(false);
3344
+ const isOpen = controlledOpen != null ? controlledOpen : internalOpen;
3345
+ const setOpen = onOpenChange != null ? onOpenChange : setInternalOpen;
3346
+ const triggerRef = useRef3(null);
3347
+ const panelRef = useRef3(null);
3348
+ useEffect3(() => {
3349
+ if (!isOpen) return;
3350
+ const handleClick = (e) => {
3351
+ if (triggerRef.current && !triggerRef.current.contains(e.target) && panelRef.current && !panelRef.current.contains(e.target)) {
3352
+ setOpen(false);
3353
+ }
3354
+ };
3355
+ document.addEventListener("mousedown", handleClick);
3356
+ return () => document.removeEventListener("mousedown", handleClick);
3357
+ }, [isOpen, setOpen]);
3358
+ return /* @__PURE__ */ jsxs46("div", __spreadProps(__spreadValues({ className: cn("ph-popover relative inline-flex", className) }, props), { children: [
3359
+ /* @__PURE__ */ jsx53(
3360
+ "div",
3361
+ {
3362
+ ref: triggerRef,
3363
+ onClick: () => setOpen(!isOpen),
3364
+ className: "ph-popover__trigger",
3365
+ children: trigger
3366
+ }
3367
+ ),
3368
+ isOpen && /* @__PURE__ */ jsx53(
3369
+ "div",
3370
+ {
3371
+ ref: panelRef,
3372
+ className: cn(
3373
+ "ph-popover__panel",
3374
+ `ph-popover--${placement}`,
3375
+ padded && "ph-popover__panel--padded",
3376
+ matchTriggerWidth && "ph-popover__panel--match"
3377
+ ),
3378
+ style: matchTriggerWidth ? { width: (_a2 = triggerRef.current) == null ? void 0 : _a2.offsetWidth } : void 0,
3379
+ children
3380
+ }
3381
+ )
3382
+ ] }));
3383
+ }
3384
+ Popover.displayName = "Popover";
3385
+
3386
+ // src/components/ui/LoadingBar.tsx
3387
+ import { jsx as jsx54 } from "react/jsx-runtime";
3388
+ function LoadingBar(_a) {
3389
+ var _b = _a, { active = true, className } = _b, props = __objRest(_b, ["active", "className"]);
3390
+ return /* @__PURE__ */ jsx54(
3391
+ "div",
3392
+ __spreadProps(__spreadValues({
3393
+ className: cn(
3394
+ "ph-loading-bar",
3395
+ active && "ph-loading-bar--active",
3396
+ className
3397
+ ),
3398
+ role: "progressbar",
3399
+ "aria-label": "Loading"
3400
+ }, props), {
3401
+ children: /* @__PURE__ */ jsx54("div", { className: "ph-loading-bar__fill" })
3402
+ })
3403
+ );
3404
+ }
3405
+ LoadingBar.displayName = "LoadingBar";
3406
+
3407
+ // src/components/ui/Link.tsx
3408
+ import { forwardRef as forwardRef10 } from "react";
3409
+ import { jsx as jsx55 } from "react/jsx-runtime";
3410
+ var Link = forwardRef10(function Link2(_a, ref) {
3411
+ var _b = _a, {
3412
+ className,
3413
+ disabled = false,
3414
+ children
3415
+ } = _b, props = __objRest(_b, [
3416
+ "className",
3417
+ "disabled",
3418
+ "children"
3419
+ ]);
3420
+ return /* @__PURE__ */ jsx55(
3421
+ "a",
3422
+ __spreadProps(__spreadValues({
3423
+ ref,
3424
+ className: cn(
3425
+ "ph-link",
3426
+ disabled && "ph-link--disabled pointer-events-none opacity-50",
3427
+ className
3428
+ ),
3429
+ tabIndex: disabled ? -1 : void 0,
3430
+ "aria-disabled": disabled || void 0
3431
+ }, props), {
3432
+ children
3433
+ })
3434
+ );
3435
+ });
3436
+ Link.displayName = "Link";
3437
+
3438
+ // src/components/ui/Spinner.tsx
3439
+ import { jsx as jsx56, jsxs as jsxs47 } from "react/jsx-runtime";
3440
+ function Spinner(_a) {
3441
+ var _b = _a, { size = "sm", textColored = false, className } = _b, props = __objRest(_b, ["size", "textColored", "className"]);
3442
+ return /* @__PURE__ */ jsx56(
3443
+ "span",
3444
+ __spreadProps(__spreadValues({
3445
+ className: cn(
3446
+ "ph-spinner",
3447
+ `ph-spinner--${size}`,
3448
+ textColored && "ph-spinner--text-colored",
3449
+ className
3450
+ ),
3451
+ role: "status",
3452
+ "aria-label": "Loading"
3453
+ }, props), {
3454
+ children: /* @__PURE__ */ jsxs47("svg", { viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "ph-spinner__svg", children: [
3455
+ /* @__PURE__ */ jsx56("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3", opacity: 0.2 }),
3456
+ /* @__PURE__ */ jsx56("path", { d: "M12 2a10 10 0 0 1 10 10", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" })
3457
+ ] })
3458
+ })
3459
+ );
3460
+ }
3461
+ Spinner.displayName = "Spinner";
3462
+
3463
+ // src/components/ui/Snack.tsx
3464
+ import { forwardRef as forwardRef11 } from "react";
3465
+ import { jsx as jsx57, jsxs as jsxs48 } from "react/jsx-runtime";
3466
+ var Snack = forwardRef11(function Snack2(_a, ref) {
3467
+ var _b = _a, {
3468
+ type = "regular",
3469
+ onClose,
3470
+ wrap = false,
3471
+ className,
3472
+ children
3473
+ } = _b, props = __objRest(_b, [
3474
+ "type",
3475
+ "onClose",
3476
+ "wrap",
3477
+ "className",
3478
+ "children"
3479
+ ]);
3480
+ return /* @__PURE__ */ jsxs48(
3481
+ "span",
3482
+ __spreadProps(__spreadValues({
3483
+ ref,
3484
+ className: cn(
3485
+ "ph-snack",
3486
+ type === "pill" && "ph-snack--pill",
3487
+ !wrap && "truncate",
3488
+ className
3489
+ ),
3490
+ title: typeof children === "string" ? children : void 0
3491
+ }, props), {
3492
+ children: [
3493
+ /* @__PURE__ */ jsx57("span", { className: "ph-snack__text", children }),
3494
+ onClose && /* @__PURE__ */ jsx57(
3495
+ "button",
3496
+ {
3497
+ type: "button",
3498
+ onClick: (e) => {
3499
+ e.stopPropagation();
3500
+ onClose();
3501
+ },
3502
+ className: "ph-snack__close",
3503
+ "aria-label": "Remove",
3504
+ children: /* @__PURE__ */ jsx57("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx57("path", { d: "M3 3l6 6M9 3l-6 6" }) })
3505
+ }
3506
+ )
3507
+ ]
3508
+ })
3509
+ );
3510
+ });
3511
+ Snack.displayName = "Snack";
3512
+
3513
+ // src/components/ui/Combobox.tsx
3514
+ import { useState as useState11, useRef as useRef4, useEffect as useEffect4 } from "react";
3515
+ import { jsx as jsx58, jsxs as jsxs49 } from "react/jsx-runtime";
3516
+ function Combobox({
3517
+ options,
3518
+ value = [],
3519
+ onChange,
3520
+ placeholder = "Search...",
3521
+ className,
3522
+ disabled
3523
+ }) {
3524
+ const [open, setOpen] = useState11(false);
3525
+ const [search, setSearch] = useState11("");
3526
+ const inputRef = useRef4(null);
3527
+ const containerRef = useRef4(null);
3528
+ const filtered = options.filter(
3529
+ (o) => o.label.toLowerCase().includes(search.toLowerCase())
3530
+ );
3531
+ const selectedSet = new Set(value);
3532
+ const toggle = (val) => {
3533
+ const next = selectedSet.has(val) ? value.filter((v) => v !== val) : [...value, val];
3534
+ onChange == null ? void 0 : onChange(next);
3535
+ };
3536
+ useEffect4(() => {
3537
+ if (!open) return;
3538
+ const handle = (e) => {
3539
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
3540
+ setOpen(false);
3541
+ }
3542
+ };
3543
+ document.addEventListener("mousedown", handle);
3544
+ return () => document.removeEventListener("mousedown", handle);
3545
+ }, [open]);
3546
+ return /* @__PURE__ */ jsxs49("div", { ref: containerRef, className: cn("ph-combobox relative", className), children: [
3547
+ /* @__PURE__ */ jsxs49("div", { className: "ph-combobox__input-wrap", children: [
3548
+ value.length > 0 && /* @__PURE__ */ jsx58("div", { className: "ph-combobox__chips", children: value.map((v) => {
3549
+ var _a, _b;
3550
+ const opt = options.find((o) => o.value === v);
3551
+ return /* @__PURE__ */ jsxs49("span", { className: "ph-combobox__chip", children: [
3552
+ (_a = opt == null ? void 0 : opt.label) != null ? _a : v,
3553
+ /* @__PURE__ */ jsx58(
3554
+ "button",
3555
+ {
3556
+ type: "button",
3557
+ onClick: () => toggle(v),
3558
+ className: "ph-combobox__chip-remove",
3559
+ "aria-label": `Remove ${(_b = opt == null ? void 0 : opt.label) != null ? _b : v}`,
3560
+ children: /* @__PURE__ */ jsx58("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx58("path", { d: "M2 2l6 6M8 2l-6 6" }) })
3561
+ }
3562
+ )
3563
+ ] }, v);
3564
+ }) }),
3565
+ /* @__PURE__ */ jsx58(
3566
+ "input",
3567
+ {
3568
+ ref: inputRef,
3569
+ type: "text",
3570
+ value: search,
3571
+ onChange: (e) => {
3572
+ setSearch(e.target.value);
3573
+ setOpen(true);
3574
+ },
3575
+ onFocus: () => setOpen(true),
3576
+ placeholder: value.length === 0 ? placeholder : "",
3577
+ disabled,
3578
+ className: "ph-combobox__input"
3579
+ }
3580
+ )
3581
+ ] }),
3582
+ open && filtered.length > 0 && /* @__PURE__ */ jsx58("div", { className: "ph-combobox__dropdown", children: filtered.map((opt) => /* @__PURE__ */ jsxs49(
3583
+ "button",
3584
+ {
3585
+ type: "button",
3586
+ onClick: () => toggle(opt.value),
3587
+ className: cn(
3588
+ "ph-combobox__option",
3589
+ selectedSet.has(opt.value) && "ph-combobox__option--selected"
3590
+ ),
3591
+ children: [
3592
+ selectedSet.has(opt.value) && /* @__PURE__ */ jsx58("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx58("path", { d: "M2.5 6l2.5 2.5 4.5-5" }) }),
3593
+ /* @__PURE__ */ jsx58("span", { children: opt.label })
3594
+ ]
3595
+ },
3596
+ opt.value
3597
+ )) })
3598
+ ] });
3599
+ }
3600
+ Combobox.displayName = "Combobox";
3601
+
3602
+ // src/components/ui/Autocomplete.tsx
3603
+ import { useState as useState12, useRef as useRef5, useEffect as useEffect5 } from "react";
3604
+ import { jsx as jsx59, jsxs as jsxs50 } from "react/jsx-runtime";
3605
+ function Autocomplete(_a) {
3606
+ var _b = _a, {
3607
+ options,
3608
+ onSelect,
3609
+ className,
3610
+ value: controlledValue,
3611
+ onChange,
3612
+ placeholder = "Type to search..."
3613
+ } = _b, inputProps = __objRest(_b, [
3614
+ "options",
3615
+ "onSelect",
3616
+ "className",
3617
+ "value",
3618
+ "onChange",
3619
+ "placeholder"
3620
+ ]);
3621
+ const [open, setOpen] = useState12(false);
3622
+ const [search, setSearch] = useState12("");
3623
+ const [activeIndex, setActiveIndex] = useState12(-1);
3624
+ const containerRef = useRef5(null);
3625
+ const inputRef = useRef5(null);
3626
+ const listRef = useRef5(null);
3627
+ const filtered = options.filter(
3628
+ (o) => o.label.toLowerCase().includes(search.toLowerCase())
3629
+ );
3630
+ const handleSelect = (opt) => {
3631
+ setSearch(opt.label);
3632
+ setOpen(false);
3633
+ onSelect == null ? void 0 : onSelect(opt);
3634
+ };
3635
+ useEffect5(() => {
3636
+ if (!open) {
3637
+ setActiveIndex(-1);
3638
+ return;
3639
+ }
3640
+ const handle = (e) => {
3641
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
3642
+ setOpen(false);
3643
+ }
3644
+ };
3645
+ const handleKey = (e) => {
3646
+ if (e.key === "ArrowDown") {
3647
+ setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
3648
+ e.preventDefault();
3649
+ }
3650
+ if (e.key === "ArrowUp") {
3651
+ setActiveIndex((i) => Math.max(i - 1, 0));
3652
+ e.preventDefault();
3653
+ }
3654
+ if (e.key === "Enter" && activeIndex >= 0) {
3655
+ handleSelect(filtered[activeIndex]);
3656
+ e.preventDefault();
3657
+ }
3658
+ if (e.key === "Escape") {
3659
+ setOpen(false);
3660
+ }
3661
+ };
3662
+ document.addEventListener("mousedown", handle);
3663
+ document.addEventListener("keydown", handleKey);
3664
+ return () => {
3665
+ document.removeEventListener("mousedown", handle);
3666
+ document.removeEventListener("keydown", handleKey);
3667
+ };
3668
+ }, [open, filtered, activeIndex]);
3669
+ useEffect5(() => {
3670
+ if (activeIndex >= 0 && listRef.current) {
3671
+ const el = listRef.current.children[activeIndex];
3672
+ el == null ? void 0 : el.scrollIntoView({ block: "nearest" });
3673
+ }
3674
+ }, [activeIndex]);
3675
+ return /* @__PURE__ */ jsxs50("div", { ref: containerRef, className: cn("ph-autocomplete relative", className), children: [
3676
+ /* @__PURE__ */ jsx59(
3677
+ "input",
3678
+ __spreadValues({
3679
+ ref: inputRef,
3680
+ type: "text",
3681
+ value: search,
3682
+ onChange: (e) => {
3683
+ setSearch(e.target.value);
3684
+ setOpen(true);
3685
+ onChange == null ? void 0 : onChange(e);
3686
+ },
3687
+ onFocus: () => setOpen(true),
3688
+ placeholder,
3689
+ className: "ph-input w-full"
3690
+ }, inputProps)
3691
+ ),
3692
+ open && filtered.length > 0 && /* @__PURE__ */ jsx59("div", { ref: listRef, className: "ph-autocomplete__dropdown", role: "listbox", children: filtered.map((opt, i) => /* @__PURE__ */ jsx59(
3693
+ "button",
3694
+ {
3695
+ type: "button",
3696
+ role: "option",
3697
+ "aria-selected": i === activeIndex,
3698
+ onMouseDown: () => handleSelect(opt),
3699
+ onMouseEnter: () => setActiveIndex(i),
3700
+ className: cn(
3701
+ "ph-autocomplete__option",
3702
+ i === activeIndex && "ph-autocomplete__option--active"
3703
+ ),
3704
+ children: opt.label
3705
+ },
3706
+ opt.value
3707
+ )) })
3708
+ ] });
3709
+ }
3710
+ Autocomplete.displayName = "Autocomplete";
3711
+
3712
+ // src/components/ui/ContextMenu.tsx
3713
+ import { useState as useState13, useRef as useRef6, useEffect as useEffect6 } from "react";
3714
+ import { jsx as jsx60, jsxs as jsxs51 } from "react/jsx-runtime";
3715
+ function ContextMenu(_a) {
3716
+ var _b = _a, { items, children, className } = _b, props = __objRest(_b, ["items", "children", "className"]);
3717
+ const [open, setOpen] = useState13(false);
3718
+ const [pos, setPos] = useState13({ x: 0, y: 0 });
3719
+ const menuRef = useRef6(null);
3720
+ useEffect6(() => {
3721
+ if (!open) return;
3722
+ const handle = (e) => {
3723
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
3724
+ setOpen(false);
3725
+ }
3726
+ };
3727
+ const handleKey = (e) => {
3728
+ if (e.key === "Escape") setOpen(false);
3729
+ };
3730
+ document.addEventListener("mousedown", handle);
3731
+ document.addEventListener("keydown", handleKey);
3732
+ return () => {
3733
+ document.removeEventListener("mousedown", handle);
3734
+ document.removeEventListener("keydown", handleKey);
3735
+ };
3736
+ }, [open]);
3737
+ return /* @__PURE__ */ jsxs51(
3738
+ "div",
3739
+ __spreadProps(__spreadValues({
3740
+ className: cn("ph-context-menu", className),
3741
+ onContextMenu: (e) => {
3742
+ e.preventDefault();
3743
+ setPos({ x: e.clientX, y: e.clientY });
3744
+ setOpen(true);
3745
+ }
3746
+ }, props), {
3747
+ children: [
3748
+ children,
3749
+ open && /* @__PURE__ */ jsx60(
3750
+ "div",
3751
+ {
3752
+ ref: menuRef,
3753
+ className: "ph-context-menu__panel",
3754
+ style: { left: pos.x, top: pos.y },
3755
+ children: items.map(
3756
+ (item, i) => item.separator ? /* @__PURE__ */ jsx60("div", { className: "ph-context-menu__separator" }, i) : /* @__PURE__ */ jsxs51(
3757
+ "button",
3758
+ {
3759
+ type: "button",
3760
+ disabled: item.disabled,
3761
+ onClick: () => {
3762
+ var _a2;
3763
+ (_a2 = item.onClick) == null ? void 0 : _a2.call(item);
3764
+ setOpen(false);
3765
+ },
3766
+ className: "ph-context-menu__item",
3767
+ children: [
3768
+ item.icon && /* @__PURE__ */ jsx60("span", { className: "ph-context-menu__icon", children: item.icon }),
3769
+ /* @__PURE__ */ jsx60("span", { children: item.label })
3770
+ ]
3771
+ },
3772
+ i
3773
+ )
3774
+ )
3775
+ }
3776
+ )
3777
+ ]
3778
+ })
3779
+ );
3780
+ }
3781
+ ContextMenu.displayName = "ContextMenu";
3782
+
3783
+ // src/components/ui/Resizable.tsx
3784
+ import { useState as useState14, useRef as useRef7, useCallback } from "react";
3785
+ import { jsx as jsx61, jsxs as jsxs52 } from "react/jsx-runtime";
3786
+ function Resizable(_a) {
3787
+ var _b = _a, {
3788
+ left,
3789
+ right,
3790
+ defaultLeftWidth = 50,
3791
+ minLeftWidth = 20,
3792
+ minRightWidth = 20,
3793
+ className
3794
+ } = _b, props = __objRest(_b, [
3795
+ "left",
3796
+ "right",
3797
+ "defaultLeftWidth",
3798
+ "minLeftWidth",
3799
+ "minRightWidth",
3800
+ "className"
3801
+ ]);
3802
+ const [leftPercent, setLeftPercent] = useState14(defaultLeftWidth);
3803
+ const dragging = useRef7(false);
3804
+ const containerRef = useRef7(null);
3805
+ const handleMouseDown = useCallback((e) => {
3806
+ e.preventDefault();
3807
+ dragging.current = true;
3808
+ const startX = e.clientX;
3809
+ const startPercent = leftPercent;
3810
+ const handleMove = (ev) => {
3811
+ if (!dragging.current || !containerRef.current) return;
3812
+ const rect = containerRef.current.getBoundingClientRect();
3813
+ const delta = (ev.clientX - startX) / rect.width * 100;
3814
+ const newVal = Math.max(minLeftWidth, Math.min(100 - minRightWidth, startPercent + delta));
3815
+ setLeftPercent(newVal);
3816
+ };
3817
+ const handleUp = () => {
3818
+ dragging.current = false;
3819
+ document.removeEventListener("mousemove", handleMove);
3820
+ document.removeEventListener("mouseup", handleUp);
3821
+ };
3822
+ document.addEventListener("mousemove", handleMove);
3823
+ document.addEventListener("mouseup", handleUp);
3824
+ }, [leftPercent, minLeftWidth, minRightWidth]);
3825
+ return /* @__PURE__ */ jsxs52(
3826
+ "div",
3827
+ __spreadProps(__spreadValues({
3828
+ ref: containerRef,
3829
+ className: cn("ph-resizable flex overflow-hidden", className)
3830
+ }, props), {
3831
+ children: [
3832
+ /* @__PURE__ */ jsx61("div", { className: "ph-resizable__left overflow-auto", style: { width: `${leftPercent}%` }, children: left }),
3833
+ /* @__PURE__ */ jsx61(
3834
+ "div",
3835
+ {
3836
+ className: "ph-resizable__handle cursor-col-resize shrink-0",
3837
+ onMouseDown: handleMouseDown
3838
+ }
3839
+ ),
3840
+ /* @__PURE__ */ jsx61("div", { className: "ph-resizable__right flex-1 overflow-auto", children: right })
3841
+ ]
3842
+ })
3843
+ );
3844
+ }
3845
+ Resizable.displayName = "Resizable";
3846
+
3847
+ // src/components/ui/ScrollArea.tsx
3848
+ import { useRef as useRef8, useState as useState15, useEffect as useEffect7 } from "react";
3849
+ import { jsx as jsx62, jsxs as jsxs53 } from "react/jsx-runtime";
3850
+ function ScrollArea(_a) {
3851
+ var _b = _a, {
3852
+ children,
3853
+ orientation = "vertical",
3854
+ className
3855
+ } = _b, props = __objRest(_b, [
3856
+ "children",
3857
+ "orientation",
3858
+ "className"
3859
+ ]);
3860
+ const viewportRef = useRef8(null);
3861
+ const [showTop, setShowTop] = useState15(false);
3862
+ const [showBottom, setShowBottom] = useState15(false);
3863
+ useEffect7(() => {
3864
+ const el = viewportRef.current;
3865
+ if (!el) return;
3866
+ const update = () => {
3867
+ setShowTop(el.scrollTop > 4);
3868
+ setShowBottom(el.scrollTop < el.scrollHeight - el.clientHeight - 4);
3869
+ };
3870
+ update();
3871
+ el.addEventListener("scroll", update, { passive: true });
3872
+ const ro = new ResizeObserver(update);
3873
+ ro.observe(el);
3874
+ return () => {
3875
+ el.removeEventListener("scroll", update);
3876
+ ro.disconnect();
3877
+ };
3878
+ }, []);
3879
+ return /* @__PURE__ */ jsxs53(
3880
+ "div",
3881
+ __spreadProps(__spreadValues({
3882
+ className: cn(
3883
+ "ph-scroll-area relative overflow-hidden",
3884
+ orientation === "horizontal" && "overflow-x-auto",
3885
+ orientation === "both" && "overflow-auto",
3886
+ className
3887
+ )
3888
+ }, props), {
3889
+ children: [
3890
+ showTop && /* @__PURE__ */ jsx62("div", { className: "ph-scroll-area__shadow-top" }),
3891
+ /* @__PURE__ */ jsx62("div", { ref: viewportRef, className: "ph-scroll-area__viewport overflow-y-auto overscroll-contain", children }),
3892
+ showBottom && /* @__PURE__ */ jsx62("div", { className: "ph-scroll-area__shadow-bottom" })
3893
+ ]
3894
+ })
3895
+ );
3896
+ }
3897
+ ScrollArea.displayName = "ScrollArea";
3898
+
3899
+ // src/components/ui/NumberField.tsx
3900
+ import { useState as useState16 } from "react";
3901
+ import { jsx as jsx63, jsxs as jsxs54 } from "react/jsx-runtime";
3902
+ function NumberField(_a) {
3903
+ var _b = _a, {
3904
+ value: controlledValue,
3905
+ onChange,
3906
+ min,
3907
+ max,
3908
+ step = 1,
3909
+ label,
3910
+ className,
3911
+ disabled,
3912
+ defaultValue
3913
+ } = _b, inputProps = __objRest(_b, [
3914
+ "value",
3915
+ "onChange",
3916
+ "min",
3917
+ "max",
3918
+ "step",
3919
+ "label",
3920
+ "className",
3921
+ "disabled",
3922
+ "defaultValue"
3923
+ ]);
3924
+ const [internal, setInternal] = useState16(controlledValue != null ? controlledValue : 0);
3925
+ const value = controlledValue != null ? controlledValue : internal;
3926
+ const set = (v) => {
3927
+ const clamped = Math.max(min != null ? min : -Infinity, Math.min(max != null ? max : Infinity, v));
3928
+ setInternal(clamped);
3929
+ onChange == null ? void 0 : onChange(clamped);
3930
+ };
3931
+ return /* @__PURE__ */ jsxs54("div", { className: cn("ph-number-field", className), children: [
3932
+ label && /* @__PURE__ */ jsx63("label", { className: "ph-label", children: label }),
3933
+ /* @__PURE__ */ jsxs54("div", { className: "ph-number-field__control", children: [
3934
+ /* @__PURE__ */ jsx63(
3935
+ "button",
3936
+ {
3937
+ type: "button",
3938
+ disabled: disabled || min !== void 0 && value <= min,
3939
+ onClick: () => set(value - step),
3940
+ className: "ph-number-field__btn",
3941
+ "aria-label": "Decrease",
3942
+ children: /* @__PURE__ */ jsx63("svg", { width: "12", height: "2", viewBox: "0 0 12 2", fill: "currentColor", children: /* @__PURE__ */ jsx63("rect", { y: "0", width: "12", height: "2", rx: "1" }) })
3943
+ }
3944
+ ),
3945
+ /* @__PURE__ */ jsx63(
3946
+ "input",
3947
+ __spreadValues({
3948
+ type: "number",
3949
+ value,
3950
+ onChange: (e) => set(Number(e.target.value)),
3951
+ disabled,
3952
+ min,
3953
+ max,
3954
+ step,
3955
+ className: "ph-number-field__input"
3956
+ }, inputProps)
3957
+ ),
3958
+ /* @__PURE__ */ jsx63(
3959
+ "button",
3960
+ {
3961
+ type: "button",
3962
+ disabled: disabled || max !== void 0 && value >= max,
3963
+ onClick: () => set(value + step),
3964
+ className: "ph-number-field__btn",
3965
+ "aria-label": "Increase",
3966
+ children: /* @__PURE__ */ jsx63("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx63("path", { d: "M6 2v8M2 6h8" }) })
3967
+ }
3968
+ )
3969
+ ] })
3970
+ ] });
3971
+ }
3972
+ NumberField.displayName = "NumberField";
3973
+
3974
+ // src/components/ui/InputGroup.tsx
3975
+ import { jsx as jsx64 } from "react/jsx-runtime";
3976
+ function InputGroup(_a) {
3977
+ var _b = _a, { children, className } = _b, props = __objRest(_b, ["children", "className"]);
3978
+ return /* @__PURE__ */ jsx64("div", __spreadProps(__spreadValues({ className: cn("ph-input-group", className) }, props), { children }));
3979
+ }
3980
+ InputGroup.displayName = "InputGroup";
3981
+
3982
+ // src/components/ui/ButtonGroup.tsx
3983
+ import { jsx as jsx65 } from "react/jsx-runtime";
3984
+ function ButtonGroup(_a) {
3985
+ var _b = _a, { children, className } = _b, props = __objRest(_b, ["children", "className"]);
3986
+ return /* @__PURE__ */ jsx65("div", __spreadProps(__spreadValues({ className: cn("ph-btn-group", className) }, props), { children }));
3987
+ }
3988
+ ButtonGroup.displayName = "ButtonGroup";
3989
+
3990
+ // src/components/ui/Toggle.tsx
3991
+ import { forwardRef as forwardRef12 } from "react";
3992
+ import { jsx as jsx66, jsxs as jsxs55 } from "react/jsx-runtime";
3993
+ var ToggleButton = forwardRef12(function ToggleButton2(_a, ref) {
3994
+ var _b = _a, {
3995
+ pressed = false,
3996
+ onPressedChange,
3997
+ icon,
3998
+ children,
3999
+ className
4000
+ } = _b, props = __objRest(_b, [
4001
+ "pressed",
4002
+ "onPressedChange",
4003
+ "icon",
4004
+ "children",
4005
+ "className"
4006
+ ]);
4007
+ return /* @__PURE__ */ jsxs55(
4008
+ "button",
4009
+ __spreadProps(__spreadValues({
4010
+ ref,
4011
+ type: "button",
4012
+ "aria-pressed": pressed,
4013
+ onClick: () => onPressedChange == null ? void 0 : onPressedChange(!pressed),
4014
+ className: cn(
4015
+ "ph-toggle-btn",
4016
+ pressed && "ph-toggle-btn--pressed",
4017
+ className
4018
+ )
4019
+ }, props), {
4020
+ children: [
4021
+ icon && /* @__PURE__ */ jsx66("span", { className: "ph-toggle-btn__icon", children: icon }),
4022
+ children
4023
+ ]
4024
+ })
4025
+ );
4026
+ });
4027
+ ToggleButton.displayName = "ToggleButton";
4028
+ function ToggleGroup({
4029
+ type = "single",
4030
+ value,
4031
+ onValueChange,
4032
+ children,
4033
+ className
4034
+ }) {
4035
+ return /* @__PURE__ */ jsx66("div", { className: cn("ph-toggle-group", className), role: "group", children });
4036
+ }
4037
+ ToggleGroup.displayName = "ToggleGroup";
4038
+
4039
+ // src/components/ui/Menubar.tsx
4040
+ import { useState as useState17, useRef as useRef9, useEffect as useEffect8 } from "react";
4041
+ import { jsx as jsx67, jsxs as jsxs56 } from "react/jsx-runtime";
4042
+ function Menubar(_a) {
4043
+ var _b = _a, { items, className } = _b, props = __objRest(_b, ["items", "className"]);
4044
+ const [openIndex, setOpenIndex] = useState17(-1);
4045
+ const barRef = useRef9(null);
4046
+ useEffect8(() => {
4047
+ if (openIndex < 0) return;
4048
+ const handle = (e) => {
4049
+ if (barRef.current && !barRef.current.contains(e.target)) {
4050
+ setOpenIndex(-1);
4051
+ }
4052
+ };
4053
+ document.addEventListener("mousedown", handle);
4054
+ return () => document.removeEventListener("mousedown", handle);
4055
+ }, [openIndex]);
4056
+ return /* @__PURE__ */ jsx67("div", __spreadProps(__spreadValues({ ref: barRef, className: cn("ph-menubar", className) }, props), { children: items.map((item, i) => /* @__PURE__ */ jsxs56("div", { className: "ph-menubar__item", children: [
4057
+ /* @__PURE__ */ jsx67(
4058
+ "button",
4059
+ {
4060
+ type: "button",
4061
+ onClick: () => setOpenIndex(openIndex === i ? -1 : i),
4062
+ className: cn("ph-menubar__trigger", openIndex === i && "ph-menubar__trigger--open"),
4063
+ children: item.label
4064
+ }
4065
+ ),
4066
+ openIndex === i && item.items && /* @__PURE__ */ jsx67("div", { className: "ph-menubar__dropdown", children: item.items.map(
4067
+ (sub, j) => sub.separator ? /* @__PURE__ */ jsx67("div", { className: "ph-menubar__separator" }, j) : /* @__PURE__ */ jsx67(
4068
+ "button",
4069
+ {
4070
+ type: "button",
4071
+ disabled: sub.disabled,
4072
+ onClick: () => {
4073
+ var _a2;
4074
+ (_a2 = sub.onClick) == null ? void 0 : _a2.call(sub);
4075
+ setOpenIndex(-1);
4076
+ },
4077
+ className: "ph-menubar__sub-item",
4078
+ children: sub.label
4079
+ },
4080
+ j
4081
+ )
4082
+ ) })
4083
+ ] }, i)) }));
4084
+ }
4085
+ Menubar.displayName = "Menubar";
4086
+
4087
+ // src/components/ui/AlertDialog.tsx
4088
+ import { useState as useState18 } from "react";
4089
+ import { jsx as jsx68, jsxs as jsxs57 } from "react/jsx-runtime";
4090
+ function AlertDialog(_a) {
4091
+ var _b = _a, {
4092
+ isOpen: openProp,
4093
+ onClose,
4094
+ onConfirm,
4095
+ confirmText = "Confirm",
4096
+ cancelText = "Cancel",
4097
+ confirmProps,
4098
+ cancelProps,
4099
+ children,
4100
+ title
4101
+ } = _b, modalProps = __objRest(_b, [
4102
+ "isOpen",
4103
+ "onClose",
4104
+ "onConfirm",
4105
+ "confirmText",
4106
+ "cancelText",
4107
+ "confirmProps",
4108
+ "cancelProps",
4109
+ "children",
4110
+ "title"
4111
+ ]);
4112
+ const [loading, setLoading] = useState18(false);
4113
+ const isOpen = openProp != null ? openProp : true;
4114
+ const handleConfirm = async () => {
4115
+ if (!onConfirm) return;
4116
+ setLoading(true);
4117
+ try {
4118
+ await onConfirm();
4119
+ } finally {
4120
+ setLoading(false);
4121
+ }
4122
+ onClose == null ? void 0 : onClose();
4123
+ };
4124
+ return /* @__PURE__ */ jsx68(
4125
+ Modal,
4126
+ __spreadProps(__spreadValues({
4127
+ open: isOpen,
4128
+ onClose,
4129
+ title,
4130
+ footer: /* @__PURE__ */ jsxs57("div", { className: "flex justify-end gap-2", children: [
4131
+ /* @__PURE__ */ jsx68(Button, __spreadProps(__spreadValues({ variant: "secondary" }, cancelProps), { onClick: onClose, children: cancelText })),
4132
+ onConfirm && /* @__PURE__ */ jsx68(Button, __spreadProps(__spreadValues({ variant: "primary", loading }, confirmProps), { onClick: handleConfirm, children: confirmText }))
4133
+ ] })
4134
+ }, modalProps), {
4135
+ children
4136
+ })
4137
+ );
4138
+ }
4139
+ AlertDialog.displayName = "AlertDialog";
4140
+
4141
+ // src/components/ui/Dot.tsx
4142
+ import { jsx as jsx69 } from "react/jsx-runtime";
4143
+ var colorMap2 = {
4144
+ green: "bg-ph-success",
4145
+ yellow: "bg-ph-warning",
4146
+ red: "bg-ph-danger",
4147
+ blue: "bg-ph-info",
4148
+ gray: "bg-ph-mutedtext"
4149
+ };
4150
+ function Dot(_a) {
4151
+ var _b = _a, { color = "gray", size = "md", className } = _b, props = __objRest(_b, ["color", "size", "className"]);
4152
+ return /* @__PURE__ */ jsx69(
4153
+ "span",
4154
+ __spreadValues({
4155
+ className: cn(
4156
+ "ph-dot inline-block shrink-0 rounded-full",
4157
+ size === "sm" ? "h-1.5 w-1.5" : "h-2.5 w-2.5",
4158
+ colorMap2[color],
4159
+ className
4160
+ ),
4161
+ "aria-hidden": "true"
4162
+ }, props)
4163
+ );
4164
+ }
4165
+ Dot.displayName = "Dot";
4166
+
4167
+ // src/components/ui/Collapsible.tsx
4168
+ import { useState as useState19 } from "react";
4169
+ import { jsx as jsx70, jsxs as jsxs58 } from "react/jsx-runtime";
4170
+ function Collapsible(_a) {
4171
+ var _b = _a, {
4172
+ trigger,
4173
+ open: controlledOpen,
4174
+ onOpenChange,
4175
+ children,
4176
+ className
4177
+ } = _b, props = __objRest(_b, [
4178
+ "trigger",
4179
+ "open",
4180
+ "onOpenChange",
4181
+ "children",
4182
+ "className"
4183
+ ]);
4184
+ const [internalOpen, setInternalOpen] = useState19(false);
4185
+ const isOpen = controlledOpen != null ? controlledOpen : internalOpen;
4186
+ const setOpen = onOpenChange != null ? onOpenChange : setInternalOpen;
4187
+ return /* @__PURE__ */ jsxs58("div", __spreadProps(__spreadValues({ className: cn("ph-collapsible", className) }, props), { children: [
4188
+ /* @__PURE__ */ jsxs58(
4189
+ "button",
4190
+ {
4191
+ type: "button",
4192
+ onClick: () => setOpen(!isOpen),
4193
+ className: "ph-collapsible__trigger",
4194
+ "aria-expanded": isOpen,
4195
+ children: [
4196
+ /* @__PURE__ */ jsx70(
4197
+ "svg",
4198
+ {
4199
+ className: cn("ph-collapsible__chevron", isOpen && "ph-collapsible__chevron--open"),
4200
+ width: "14",
4201
+ height: "14",
4202
+ viewBox: "0 0 14 14",
4203
+ fill: "none",
4204
+ stroke: "currentColor",
4205
+ strokeWidth: "2",
4206
+ strokeLinecap: "round",
4207
+ children: /* @__PURE__ */ jsx70("path", { d: "M4 5l3 3 3-3" })
4208
+ }
4209
+ ),
4210
+ trigger
4211
+ ]
4212
+ }
4213
+ ),
4214
+ isOpen && /* @__PURE__ */ jsx70("div", { className: "ph-collapsible__content", children })
4215
+ ] }));
4216
+ }
4217
+ Collapsible.displayName = "Collapsible";
4218
+
4219
+ // src/components/ui/Metric.tsx
4220
+ import { jsx as jsx71, jsxs as jsxs59 } from "react/jsx-runtime";
4221
+ function Metric(_a) {
4222
+ var _b = _a, {
4223
+ value,
4224
+ label,
4225
+ badge,
4226
+ trend,
4227
+ icon,
4228
+ className
4229
+ } = _b, props = __objRest(_b, [
4230
+ "value",
4231
+ "label",
4232
+ "badge",
4233
+ "trend",
4234
+ "icon",
4235
+ "className"
4236
+ ]);
4237
+ return /* @__PURE__ */ jsxs59("div", __spreadProps(__spreadValues({ className: cn("ph-metric", className) }, props), { children: [
4238
+ /* @__PURE__ */ jsxs59("div", { className: "ph-metric__header", children: [
4239
+ icon && /* @__PURE__ */ jsx71("span", { className: "ph-metric__icon", children: icon }),
4240
+ /* @__PURE__ */ jsx71("span", { className: "ph-metric__label", children: label }),
4241
+ badge && /* @__PURE__ */ jsx71("span", { className: "ph-metric__badge", children: badge })
4242
+ ] }),
4243
+ /* @__PURE__ */ jsx71("div", { className: "ph-metric__value", children: value }),
4244
+ trend && /* @__PURE__ */ jsx71("div", { className: "ph-metric__trend", children: trend })
4245
+ ] }));
4246
+ }
4247
+ Metric.displayName = "Metric";
4248
+
4249
+ // src/components/ui/Chip.tsx
4250
+ import { forwardRef as forwardRef13 } from "react";
4251
+ import { jsx as jsx72, jsxs as jsxs60 } from "react/jsx-runtime";
4252
+ var Chip = forwardRef13(function Chip2(_a, ref) {
4253
+ var _b = _a, {
4254
+ selected = false,
4255
+ onRemove,
4256
+ children,
4257
+ className
4258
+ } = _b, props = __objRest(_b, [
4259
+ "selected",
4260
+ "onRemove",
4261
+ "children",
4262
+ "className"
4263
+ ]);
4264
+ return /* @__PURE__ */ jsxs60(
4265
+ "button",
4266
+ __spreadProps(__spreadValues({
4267
+ ref,
4268
+ type: "button",
4269
+ className: cn(
4270
+ "ph-chip",
4271
+ selected && "ph-chip--selected",
4272
+ className
4273
+ )
4274
+ }, props), {
4275
+ children: [
4276
+ /* @__PURE__ */ jsx72("span", { className: "ph-chip__text", children }),
4277
+ onRemove && /* @__PURE__ */ jsx72(
4278
+ "span",
4279
+ {
4280
+ role: "button",
4281
+ tabIndex: -1,
4282
+ onClick: (e) => {
4283
+ e.stopPropagation();
4284
+ onRemove();
4285
+ },
4286
+ className: "ph-chip__remove",
4287
+ "aria-label": "Remove",
4288
+ children: /* @__PURE__ */ jsx72("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx72("path", { d: "M2 2l6 6M8 2l-6 6" }) })
4289
+ }
4290
+ )
4291
+ ]
4292
+ })
4293
+ );
4294
+ });
4295
+ Chip.displayName = "Chip";
4296
+
4297
+ // src/components/ui/DataTable.tsx
4298
+ import { useState as useState20, useMemo } from "react";
4299
+ import { jsx as jsx73, jsxs as jsxs61 } from "react/jsx-runtime";
4300
+ function DataTable({
4301
+ columns,
4302
+ data,
4303
+ pageSize = 10,
4304
+ searchable = false,
4305
+ searchPlaceholder = "Search...",
4306
+ className
4307
+ }) {
4308
+ const [search, setSearch] = useState20("");
4309
+ const [sortKey, setSortKey] = useState20(null);
4310
+ const [sortDir, setSortDir] = useState20("asc");
4311
+ const [page, setPage] = useState20(0);
4312
+ const filtered = useMemo(() => {
4313
+ let items = data;
4314
+ if (search) {
4315
+ const q = search.toLowerCase();
4316
+ items = items.filter(
4317
+ (item) => Object.values(item).some((v) => String(v).toLowerCase().includes(q))
4318
+ );
4319
+ }
4320
+ if (sortKey) {
4321
+ items = [...items].sort((a, b) => {
4322
+ const av = a[sortKey];
4323
+ const bv = b[sortKey];
4324
+ const cmp = av < bv ? -1 : av > bv ? 1 : 0;
4325
+ return sortDir === "asc" ? cmp : -cmp;
4326
+ });
4327
+ }
4328
+ return items;
4329
+ }, [data, search, sortKey, sortDir]);
4330
+ const totalPages = Math.ceil(filtered.length / pageSize);
4331
+ const paged = filtered.slice(page * pageSize, (page + 1) * pageSize);
4332
+ const handleSort = (key) => {
4333
+ if (sortKey === key) {
4334
+ setSortDir((d) => d === "asc" ? "desc" : "asc");
4335
+ } else {
4336
+ setSortKey(key);
4337
+ setSortDir("asc");
4338
+ }
4339
+ };
4340
+ return /* @__PURE__ */ jsxs61("div", { className: cn("ph-data-table", className), children: [
4341
+ searchable && /* @__PURE__ */ jsx73("div", { className: "ph-data-table__toolbar", children: /* @__PURE__ */ jsx73(
4342
+ "input",
4343
+ {
4344
+ type: "text",
4345
+ value: search,
4346
+ onChange: (e) => {
4347
+ setSearch(e.target.value);
4348
+ setPage(0);
4349
+ },
4350
+ placeholder: searchPlaceholder,
4351
+ className: "ph-input ph-input-sm"
4352
+ }
4353
+ ) }),
4354
+ /* @__PURE__ */ jsx73("div", { className: "ph-table-wrap", children: /* @__PURE__ */ jsxs61("table", { className: "ph-table", children: [
4355
+ /* @__PURE__ */ jsx73("thead", { children: /* @__PURE__ */ jsx73("tr", { children: columns.map((col) => /* @__PURE__ */ jsxs61(
4356
+ "th",
4357
+ {
4358
+ className: cn(col.sortable && "cursor-pointer select-none", col.className),
4359
+ onClick: () => col.sortable && handleSort(col.key),
4360
+ children: [
4361
+ col.label,
4362
+ sortKey === col.key && /* @__PURE__ */ jsx73("span", { className: "ml-1 inline-block", children: sortDir === "asc" ? "\u2191" : "\u2193" })
4363
+ ]
4364
+ },
4365
+ col.key
4366
+ )) }) }),
4367
+ /* @__PURE__ */ jsxs61("tbody", { children: [
4368
+ paged.map((item, i) => /* @__PURE__ */ jsx73("tr", { children: columns.map((col) => /* @__PURE__ */ jsx73("td", { className: col.className, children: col.render ? col.render(item) : item[col.key] }, col.key)) }, i)),
4369
+ paged.length === 0 && /* @__PURE__ */ jsx73("tr", { children: /* @__PURE__ */ jsx73("td", { colSpan: columns.length, className: "text-center text-ph-mutedtext py-8", children: "No results" }) })
4370
+ ] })
4371
+ ] }) }),
4372
+ totalPages > 1 && /* @__PURE__ */ jsxs61("div", { className: "ph-data-table__pagination", children: [
4373
+ /* @__PURE__ */ jsx73("button", { disabled: page === 0, onClick: () => setPage((p) => p - 1), className: "ph-data-table__page-btn", children: "Previous" }),
4374
+ /* @__PURE__ */ jsxs61("span", { className: "text-xs text-ph-mutedtext", children: [
4375
+ "Page ",
4376
+ page + 1,
4377
+ " of ",
4378
+ totalPages
4379
+ ] }),
4380
+ /* @__PURE__ */ jsx73("button", { disabled: page >= totalPages - 1, onClick: () => setPage((p) => p + 1), className: "ph-data-table__page-btn", children: "Next" })
4381
+ ] })
4382
+ ] });
4383
+ }
4384
+ DataTable.displayName = "DataTable";
4385
+
4386
+ // src/components/ui/DatePicker.tsx
4387
+ import { useState as useState21, useMemo as useMemo2 } from "react";
4388
+ import { jsx as jsx74, jsxs as jsxs62 } from "react/jsx-runtime";
4389
+ var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
4390
+ var DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
4391
+ function DatePicker(_a) {
4392
+ var _b = _a, { value, onChange, className } = _b, props = __objRest(_b, ["value", "onChange", "className"]);
4393
+ const [open, setOpen] = useState21(false);
4394
+ const [viewDate, setViewDate] = useState21(value != null ? value : /* @__PURE__ */ new Date());
4395
+ const selected = value;
4396
+ const days = useMemo2(() => {
4397
+ const year = viewDate.getFullYear();
4398
+ const month = viewDate.getMonth();
4399
+ const first = new Date(year, month, 1).getDay();
4400
+ const last = new Date(year, month + 1, 0).getDate();
4401
+ const prevLast = new Date(year, month, 0).getDate();
4402
+ const cells = [];
4403
+ for (let i = first - 1; i >= 0; i--) cells.push({ day: prevLast - i, month: "prev" });
4404
+ for (let d = 1; d <= last; d++) cells.push({ day: d, month: "current" });
4405
+ const remaining = 42 - cells.length;
4406
+ for (let d = 1; d <= remaining; d++) cells.push({ day: d, month: "next" });
4407
+ return cells;
4408
+ }, [viewDate]);
4409
+ const isSelected = (d, m) => {
4410
+ if (!selected || m !== "current") return false;
4411
+ const date = new Date(viewDate.getFullYear(), viewDate.getMonth(), d);
4412
+ return date.toDateString() === selected.toDateString();
4413
+ };
4414
+ const selectDay = (d, m) => {
4415
+ const month = m === "prev" ? viewDate.getMonth() - 1 : m === "next" ? viewDate.getMonth() + 1 : viewDate.getMonth();
4416
+ const year = month < 0 ? viewDate.getFullYear() - 1 : month > 11 ? viewDate.getFullYear() + 1 : viewDate.getFullYear();
4417
+ const adjustedMonth = (month % 12 + 12) % 12;
4418
+ const date = new Date(year, adjustedMonth, d);
4419
+ onChange == null ? void 0 : onChange(date);
4420
+ setOpen(false);
4421
+ };
4422
+ const nav = (delta) => setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() + delta, 1));
4423
+ return /* @__PURE__ */ jsxs62("div", { className: cn("ph-datepicker relative", className), children: [
4424
+ /* @__PURE__ */ jsx74(
4425
+ "input",
4426
+ __spreadValues({
4427
+ type: "text",
4428
+ readOnly: true,
4429
+ value: selected ? `${MONTHS[selected.getMonth()]} ${selected.getDate()}, ${selected.getFullYear()}` : "",
4430
+ onFocus: () => setOpen(true),
4431
+ placeholder: "Pick a date",
4432
+ className: "ph-input w-full cursor-pointer"
4433
+ }, props)
4434
+ ),
4435
+ open && /* @__PURE__ */ jsxs62("div", { className: "ph-datepicker__dropdown", children: [
4436
+ /* @__PURE__ */ jsxs62("div", { className: "ph-datepicker__nav", children: [
4437
+ /* @__PURE__ */ jsx74("button", { type: "button", onClick: () => nav(-1), className: "ph-datepicker__nav-btn", "aria-label": "Previous month", children: /* @__PURE__ */ jsx74("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx74("path", { d: "M7 3L4 6l3 3" }) }) }),
4438
+ /* @__PURE__ */ jsxs62("span", { className: "ph-datepicker__nav-label", children: [
4439
+ MONTHS[viewDate.getMonth()],
4440
+ " ",
4441
+ viewDate.getFullYear()
4442
+ ] }),
4443
+ /* @__PURE__ */ jsx74("button", { type: "button", onClick: () => nav(1), className: "ph-datepicker__nav-btn", "aria-label": "Next month", children: /* @__PURE__ */ jsx74("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx74("path", { d: "M5 3l3 3-3 3" }) }) })
4444
+ ] }),
4445
+ /* @__PURE__ */ jsxs62("div", { className: "ph-datepicker__grid", children: [
4446
+ DAYS.map((d) => /* @__PURE__ */ jsx74("div", { className: "ph-datepicker__day-header", children: d }, d)),
4447
+ days.map((d, i) => /* @__PURE__ */ jsx74(
4448
+ "button",
4449
+ {
4450
+ type: "button",
4451
+ disabled: d.month !== "current",
4452
+ onClick: () => selectDay(d.day, d.month),
4453
+ className: cn(
4454
+ "ph-datepicker__day",
4455
+ d.month !== "current" && "ph-datepicker__day--other",
4456
+ isSelected(d.day, d.month) && "ph-datepicker__day--selected"
4457
+ ),
4458
+ children: d.day
4459
+ },
4460
+ i
4461
+ ))
4462
+ ] })
4463
+ ] })
4464
+ ] });
4465
+ }
4466
+ DatePicker.displayName = "DatePicker";
4467
+
4468
+ // src/components/ui/AppLayout.tsx
4469
+ import { jsx as jsx75, jsxs as jsxs63 } from "react/jsx-runtime";
4470
+ function AppLayout({ sidebar, children, sidebarWidth = 240, className }) {
4471
+ return /* @__PURE__ */ jsxs63(
4472
+ "div",
4473
+ {
4474
+ className: cn("ph-app-layout grid min-h-screen", className),
4475
+ style: { gridTemplateColumns: `${sidebarWidth}px minmax(0, 1fr)` },
4476
+ children: [
4477
+ /* @__PURE__ */ jsx75("aside", { className: "ph-app-layout__sidebar border-r border-ph-border bg-ph-surface overflow-y-auto", children: sidebar }),
4478
+ /* @__PURE__ */ jsx75("main", { className: "ph-app-layout__content min-w-0 overflow-y-auto bg-ph-canvas", children })
4479
+ ]
4480
+ }
4481
+ );
4482
+ }
4483
+
4484
+ // src/components/ui/Sidebar.tsx
4485
+ import { jsx as jsx76, jsxs as jsxs64 } from "react/jsx-runtime";
4486
+ function Sidebar({ groups, className, header, footer, children, collapsed = false, onCollapse }) {
4487
+ return /* @__PURE__ */ jsxs64("nav", { className: cn("ph-sidebar flex flex-col h-full", collapsed && "ph-sidebar--collapsed", className), children: [
4488
+ header && /* @__PURE__ */ jsx76("div", { className: "ph-sidebar__header px-3 py-3 border-b border-ph-border-subtle", children: header }),
4489
+ /* @__PURE__ */ jsx76("div", { className: "ph-sidebar__body flex-1 overflow-y-auto px-2 py-3 space-y-5", children: groups.map((group) => {
4490
+ var _a;
4491
+ return /* @__PURE__ */ jsxs64("div", { className: "ph-sidebar__group", children: [
4492
+ group.label && !collapsed && /* @__PURE__ */ jsx76("h3", { className: "ph-sidebar__group-label px-2 mb-1 text-[10px] font-semibold uppercase tracking-wider text-ph-mutedtext", children: group.label }),
4493
+ /* @__PURE__ */ jsx76("div", { className: "ph-sidebar__items space-y-0.5", children: group.items.map((item) => /* @__PURE__ */ jsx76(SidebarItem, __spreadProps(__spreadValues({}, item), { collapsed }), item.label)) })
4494
+ ] }, (_a = group.label) != null ? _a : "default");
4495
+ }) }),
4496
+ children,
4497
+ footer && /* @__PURE__ */ jsx76("div", { className: "ph-sidebar__footer px-3 py-3 border-t border-ph-border-subtle", children: footer })
4498
+ ] });
4499
+ }
4500
+ function SidebarItem({ label, icon, badge, active, href, onClick, collapsed }) {
4501
+ const Comp = onClick ? "button" : "a";
4502
+ return /* @__PURE__ */ jsxs64(
4503
+ Comp,
4504
+ {
4505
+ type: onClick ? "button" : void 0,
4506
+ href: onClick ? void 0 : href,
4507
+ onClick,
4508
+ className: cn(
4509
+ "ph-sidebar__item flex items-center gap-2.5 w-full rounded-md px-2.5 py-2 text-sm text-left transition",
4510
+ active ? "bg-ph-selected-bg text-ph-selected-text font-medium" : "text-ph-subtle hover:bg-ph-muted hover:text-ph-ink",
4511
+ collapsed && "justify-center px-2"
4512
+ ),
4513
+ title: collapsed ? label : void 0,
4514
+ children: [
4515
+ icon && /* @__PURE__ */ jsx76("span", { className: cn("ph-sidebar__item-icon shrink-0 flex items-center justify-center", collapsed ? "w-5 h-5" : "w-4 h-4"), children: icon }),
4516
+ !collapsed && /* @__PURE__ */ jsx76("span", { className: "ph-sidebar__item-label truncate flex-1", children: label }),
4517
+ !collapsed && badge && /* @__PURE__ */ jsx76("span", { className: "ph-sidebar__item-badge shrink-0", children: badge })
4518
+ ]
4519
+ }
4520
+ );
4521
+ }
4522
+ Sidebar.displayName = "Sidebar";
4523
+
4524
+ export {
4525
+ Button,
4526
+ Alert,
4527
+ Badge,
4528
+ Card,
4529
+ Drawer,
4530
+ Kbd,
4531
+ Loader,
4532
+ Skeleton,
4533
+ LoadingState,
4534
+ AuthLayout,
4535
+ AuthCard,
4536
+ AuthDivider,
4537
+ SettingsNav,
4538
+ SettingsLayout,
4539
+ FormField,
4540
+ Input,
4541
+ Select,
4542
+ Textarea,
4543
+ Checkbox,
4544
+ Radio,
4545
+ Toggle,
4546
+ Range,
4547
+ FileUpload,
4548
+ Modal,
4549
+ Breadcrumbs,
4550
+ Pagination,
4551
+ Panel,
4552
+ Rating,
4553
+ SearchInput,
4554
+ SearchGroup,
4555
+ Table,
4556
+ Stat,
4557
+ Toast,
4558
+ ToastStack,
4559
+ Tabs,
4560
+ DEFAULT_THEME_ID,
4561
+ THEMES,
4562
+ THEME_GROUPS,
4563
+ isThemeId,
4564
+ getTheme,
4565
+ THEME_INIT_SCRIPT,
4566
+ persistTheme,
4567
+ readStoredTheme,
4568
+ ThemeDomSync,
4569
+ ThemeManager,
4570
+ ThemeSwitcher,
4571
+ Accordion,
4572
+ Stepper,
4573
+ SegmentedControl,
4574
+ CommandPalette,
4575
+ Calendar,
4576
+ HoverCard,
4577
+ EmptyState,
4578
+ FilterChips,
4579
+ FilterBar,
4580
+ FilterMenu,
4581
+ SortMenu,
4582
+ FilterControls,
4583
+ CodeBlock,
4584
+ ComponentDocs,
4585
+ ShowcaseWrapper,
4586
+ CollapsibleSection,
4587
+ Display,
4588
+ H1,
4589
+ H2,
4590
+ H3,
4591
+ H4,
4592
+ H5,
4593
+ P,
4594
+ Small,
4595
+ Caption,
4596
+ Overline,
4597
+ Lead,
4598
+ Mono,
4599
+ Label,
4600
+ Avatar,
4601
+ AvatarGroup,
4602
+ Progress,
4603
+ ChatBubble,
4604
+ Terminal,
4605
+ Indicator,
4606
+ Timeline,
4607
+ Banner,
4608
+ Dialog2 as Dialog,
4609
+ Divider,
4610
+ Tag,
4611
+ ProgressCircle,
4612
+ Row,
4613
+ Widget,
4614
+ Lettermark,
4615
+ Splotch,
4616
+ Popover,
4617
+ LoadingBar,
4618
+ Link,
4619
+ Spinner,
4620
+ Snack,
4621
+ Combobox,
4622
+ Autocomplete,
4623
+ ContextMenu,
4624
+ Resizable,
4625
+ ScrollArea,
4626
+ NumberField,
4627
+ InputGroup,
4628
+ ButtonGroup,
4629
+ ToggleButton,
4630
+ ToggleGroup,
4631
+ Menubar,
4632
+ AlertDialog,
4633
+ Dot,
4634
+ Collapsible,
4635
+ Metric,
4636
+ Chip,
4637
+ DataTable,
4638
+ DatePicker,
4639
+ AppLayout,
4640
+ Sidebar
4641
+ };