@xenide-io/the-old-ui-theme 0.5.4 → 0.6.0

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