@yarvelle/ui 0.0.0-stage → 0.1.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 (42) hide show
  1. package/bin/yarvelle-ui-codegen.js +115 -0
  2. package/dist/index-DLbrj3Po.d.ts +90 -0
  3. package/dist/index.d.ts +706 -0
  4. package/dist/index.js +4418 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/api/index.d.ts +99 -0
  7. package/dist/lib/api/index.js +113 -0
  8. package/dist/lib/api/index.js.map +1 -0
  9. package/dist/lib/auth/index.d.ts +21 -0
  10. package/dist/lib/auth/index.js +37 -0
  11. package/dist/lib/auth/index.js.map +1 -0
  12. package/dist/lib/cn.d.ts +5 -0
  13. package/dist/lib/cn.js +10 -0
  14. package/dist/lib/cn.js.map +1 -0
  15. package/dist/lib/i18n/index.d.ts +7 -0
  16. package/dist/lib/i18n/index.js +45 -0
  17. package/dist/lib/i18n/index.js.map +1 -0
  18. package/dist/lib/index.d.ts +8 -0
  19. package/dist/lib/index.js +272 -0
  20. package/dist/lib/index.js.map +1 -0
  21. package/dist/lib/sse/index.d.ts +11 -0
  22. package/dist/lib/sse/index.js +43 -0
  23. package/dist/lib/sse/index.js.map +1 -0
  24. package/dist/lib/storage-namespace.d.ts +6 -0
  25. package/dist/lib/storage-namespace.js +34 -0
  26. package/dist/lib/storage-namespace.js.map +1 -0
  27. package/dist/slots/index.d.ts +12 -0
  28. package/dist/slots/index.js +86 -0
  29. package/dist/slots/index.js.map +1 -0
  30. package/dist/styles.css +270 -0
  31. package/dist/testing/index.d.ts +3 -0
  32. package/dist/testing/index.js +36 -0
  33. package/dist/testing/index.js.map +1 -0
  34. package/dist/tokens/index.d.ts +37 -0
  35. package/dist/tokens/index.js +155 -0
  36. package/dist/tokens/index.js.map +1 -0
  37. package/dist/tokens/tailwind-preset.d.ts +5 -0
  38. package/dist/tokens/tailwind-preset.js +155 -0
  39. package/dist/tokens/tailwind-preset.js.map +1 -0
  40. package/dist/types-CP_CDg6G.d.ts +51 -0
  41. package/package.json +69 -4
  42. package/README.md +0 -3
package/dist/index.js ADDED
@@ -0,0 +1,4418 @@
1
+ // src/tokens/tailwind-preset.ts
2
+ var yarvellePreset = {
3
+ content: [],
4
+ darkMode: ["class", '[data-theme="dark"]'],
5
+ theme: {
6
+ colors: {
7
+ transparent: "transparent",
8
+ current: "currentColor",
9
+ canvas: "var(--ui-canvas)",
10
+ surface: {
11
+ DEFAULT: "var(--ui-surface)",
12
+ 2: "var(--ui-surface-2)",
13
+ 3: "var(--ui-surface-3)"
14
+ },
15
+ rail: "var(--ui-rail)",
16
+ overlay: "var(--ui-overlay)",
17
+ fg: {
18
+ DEFAULT: "var(--ui-fg)",
19
+ muted: "var(--ui-fg-muted)",
20
+ subtle: "var(--ui-fg-subtle)",
21
+ "on-primary": "var(--ui-fg-on-primary)",
22
+ link: "var(--ui-fg-link)"
23
+ },
24
+ border: {
25
+ DEFAULT: "var(--ui-border)",
26
+ strong: "var(--ui-border-strong)"
27
+ },
28
+ primary: {
29
+ DEFAULT: "var(--ui-primary)",
30
+ hover: "var(--ui-primary-hover)",
31
+ fg: "var(--ui-primary-fg)",
32
+ soft: "var(--ui-primary-soft)",
33
+ "soft-fg": "var(--ui-primary-soft-fg)"
34
+ },
35
+ info: {
36
+ bg: "var(--ui-info-bg)",
37
+ fg: "var(--ui-info-fg)",
38
+ border: "var(--ui-info-border)"
39
+ },
40
+ warn: {
41
+ bg: "var(--ui-warn-bg)",
42
+ fg: "var(--ui-warn-fg)",
43
+ border: "var(--ui-warn-border)"
44
+ },
45
+ danger: {
46
+ bg: "var(--ui-danger-bg)",
47
+ fg: "var(--ui-danger-fg)",
48
+ border: "var(--ui-danger-border)"
49
+ },
50
+ success: {
51
+ bg: "var(--ui-success-bg)",
52
+ fg: "var(--ui-success-fg)",
53
+ border: "var(--ui-success-border)"
54
+ },
55
+ emergency: {
56
+ DEFAULT: "var(--ui-emergency)",
57
+ fg: "var(--ui-emergency-fg)"
58
+ },
59
+ focus: {
60
+ DEFAULT: "var(--ui-focus)",
61
+ offset: "var(--ui-focus-offset)"
62
+ },
63
+ member: {
64
+ 1: { bg: "var(--ui-member-1-bg)", fg: "var(--ui-member-1-fg)" },
65
+ 2: { bg: "var(--ui-member-2-bg)", fg: "var(--ui-member-2-fg)" },
66
+ 3: { bg: "var(--ui-member-3-bg)", fg: "var(--ui-member-3-fg)" },
67
+ 4: { bg: "var(--ui-member-4-bg)", fg: "var(--ui-member-4-fg)" },
68
+ 5: { bg: "var(--ui-member-5-bg)", fg: "var(--ui-member-5-fg)" }
69
+ },
70
+ scope: {
71
+ health: { bg: "var(--ui-scope-health-bg)", fg: "var(--ui-scope-health-fg)" },
72
+ finance: { bg: "var(--ui-scope-finance-bg)", fg: "var(--ui-scope-finance-fg)" },
73
+ education: { bg: "var(--ui-scope-education-bg)", fg: "var(--ui-scope-education-fg)" },
74
+ household: { bg: "var(--ui-scope-household-bg)", fg: "var(--ui-scope-household-fg)" }
75
+ },
76
+ risk: {
77
+ low: { bg: "var(--ui-risk-low-bg)", fg: "var(--ui-risk-low-fg)", border: "var(--ui-risk-low-border)" },
78
+ medium: { bg: "var(--ui-risk-medium-bg)", fg: "var(--ui-risk-medium-fg)", border: "var(--ui-risk-medium-border)" },
79
+ high: { bg: "var(--ui-risk-high-bg)", fg: "var(--ui-risk-high-fg)", border: "var(--ui-risk-high-border)" },
80
+ critical: { bg: "var(--ui-risk-critical-bg)", fg: "var(--ui-risk-critical-fg)", border: "var(--ui-risk-critical-border)" }
81
+ }
82
+ },
83
+ spacing: {
84
+ 0: "var(--ui-space-0)",
85
+ 1: "var(--ui-space-1)",
86
+ 2: "var(--ui-space-2)",
87
+ 3: "var(--ui-space-3)",
88
+ 4: "var(--ui-space-4)",
89
+ 5: "var(--ui-space-5)",
90
+ 6: "var(--ui-space-6)",
91
+ 8: "var(--ui-space-8)",
92
+ 10: "var(--ui-space-10)",
93
+ 12: "var(--ui-space-12)",
94
+ 16: "var(--ui-space-16)"
95
+ },
96
+ fontFamily: {
97
+ sans: ["var(--ui-font-sans)"],
98
+ display: ["var(--ui-font-display)"],
99
+ mono: ["var(--ui-font-mono)"]
100
+ },
101
+ fontSize: {
102
+ xs: ["var(--ui-text-xs)", { lineHeight: "var(--ui-leading-xs)" }],
103
+ sm: ["var(--ui-text-sm)", { lineHeight: "var(--ui-leading-sm)" }],
104
+ base: ["var(--ui-text-md)", { lineHeight: "var(--ui-leading-md)" }],
105
+ md: ["var(--ui-text-md)", { lineHeight: "var(--ui-leading-md)" }],
106
+ lg: ["var(--ui-text-lg)", { lineHeight: "var(--ui-leading-lg)" }],
107
+ xl: ["var(--ui-text-xl)", { lineHeight: "var(--ui-leading-xl)" }],
108
+ "2xl": ["var(--ui-text-2xl)", { lineHeight: "var(--ui-leading-2xl)" }],
109
+ "3xl": ["var(--ui-text-3xl)", { lineHeight: "var(--ui-leading-3xl)" }],
110
+ "4xl": ["var(--ui-text-4xl)", { lineHeight: "var(--ui-leading-4xl)" }]
111
+ },
112
+ borderRadius: {
113
+ none: "0px",
114
+ sm: "var(--ui-radius-sm)",
115
+ md: "var(--ui-radius-md)",
116
+ lg: "var(--ui-radius-lg)",
117
+ xl: "var(--ui-radius-xl)",
118
+ full: "var(--ui-radius-full)"
119
+ },
120
+ boxShadow: {
121
+ 0: "var(--ui-shadow-0)",
122
+ 1: "var(--ui-shadow-1)",
123
+ 2: "var(--ui-shadow-2)",
124
+ 3: "var(--ui-shadow-3)"
125
+ },
126
+ minHeight: {
127
+ tap: "var(--ui-tap)"
128
+ },
129
+ minWidth: {
130
+ tap: "var(--ui-tap)"
131
+ },
132
+ transitionTimingFunction: {
133
+ ui: "var(--ui-ease)"
134
+ },
135
+ transitionDuration: {
136
+ fast: "var(--ui-duration-fast)",
137
+ base: "var(--ui-duration-base)",
138
+ slow: "var(--ui-duration-slow)"
139
+ },
140
+ zIndex: {
141
+ rail: "var(--ui-z-rail)",
142
+ sticky: "var(--ui-z-sticky)",
143
+ popover: "var(--ui-z-popover)",
144
+ modal: "var(--ui-z-modal)",
145
+ toast: "var(--ui-z-toast)",
146
+ skip: "var(--ui-z-skip)"
147
+ }
148
+ }
149
+ };
150
+
151
+ // src/primitives/Button.tsx
152
+ import * as React from "react";
153
+
154
+ // src/lib/cn.ts
155
+ import { clsx } from "clsx";
156
+ import { twMerge } from "tailwind-merge";
157
+ function cn(...inputs) {
158
+ return twMerge(clsx(inputs));
159
+ }
160
+
161
+ // src/primitives/Button.tsx
162
+ import { jsx, jsxs } from "react/jsx-runtime";
163
+ var variantStyles = {
164
+ primary: "bg-primary hover:bg-primary-hover active:bg-primary-hover text-primary-fg border border-transparent shadow-1",
165
+ secondary: "bg-surface hover:bg-surface-2 active:bg-surface-3 text-fg border border-border-strong shadow-1",
166
+ ghost: "bg-transparent hover:bg-surface-2 active:bg-surface-3 text-fg-muted hover:text-fg border border-transparent",
167
+ outline: "bg-transparent hover:bg-surface-2 active:bg-surface-3 text-fg border border-border-strong",
168
+ danger: "bg-danger-bg hover:bg-danger-fg text-danger-fg hover:text-white border border-danger-border"
169
+ };
170
+ var sizeStyles = {
171
+ sm: "h-[34px] px-3 text-sm rounded-md relative before:absolute before:-inset-y-1.5 before:inset-x-0 before:content-['']",
172
+ md: "min-h-[44px] h-10 px-4 text-sm rounded-md",
173
+ lg: "min-h-[48px] h-12 px-5 text-base rounded-md"
174
+ };
175
+ var Button = React.forwardRef(
176
+ ({
177
+ variant = "primary",
178
+ size = "md",
179
+ loading = false,
180
+ disabled = false,
181
+ leftIcon,
182
+ rightIcon,
183
+ children,
184
+ className,
185
+ type = "button",
186
+ ...props
187
+ }, ref) => {
188
+ const isDisabled = disabled || loading;
189
+ return /* @__PURE__ */ jsxs(
190
+ "button",
191
+ {
192
+ ref,
193
+ type,
194
+ disabled: isDisabled,
195
+ "data-slot": "button",
196
+ "data-variant": variant,
197
+ "data-size": size,
198
+ "data-loading": loading ? "true" : void 0,
199
+ className: cn(
200
+ "yc-Button-root inline-flex items-center justify-center font-medium select-none",
201
+ "transition-colors duration-fast ease-ui",
202
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2",
203
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none",
204
+ variantStyles[variant],
205
+ sizeStyles[size],
206
+ className
207
+ ),
208
+ ...props,
209
+ children: [
210
+ loading ? /* @__PURE__ */ jsx(
211
+ "span",
212
+ {
213
+ className: "yc-Button-spinner me-2 inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent",
214
+ "data-slot": "spinner",
215
+ role: "status",
216
+ "aria-label": "Loading"
217
+ }
218
+ ) : leftIcon ? /* @__PURE__ */ jsx("span", { className: "yc-Button-icon yc-Button-icon-start me-2 inline-flex shrink-0 items-center", "data-slot": "icon-start", children: leftIcon }) : null,
219
+ /* @__PURE__ */ jsx("span", { className: "yc-Button-label truncate", "data-slot": "label", children }),
220
+ !loading && rightIcon ? /* @__PURE__ */ jsx("span", { className: "yc-Button-icon yc-Button-icon-end ms-2 inline-flex shrink-0 items-center", "data-slot": "icon-end", children: rightIcon }) : null
221
+ ]
222
+ }
223
+ );
224
+ }
225
+ );
226
+ Button.displayName = "Button";
227
+
228
+ // src/primitives/Dialog.tsx
229
+ import * as React2 from "react";
230
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
231
+ var DialogContext = React2.createContext(null);
232
+ function useDialogContext() {
233
+ const context = React2.useContext(DialogContext);
234
+ if (!context) {
235
+ throw new Error("Dialog compound components must be rendered within a <Dialog>");
236
+ }
237
+ return context;
238
+ }
239
+ function Dialog({
240
+ open: controlledOpen,
241
+ defaultOpen = false,
242
+ onOpenChange,
243
+ children
244
+ }) {
245
+ const [uncontrolledOpen, setUncontrolledOpen] = React2.useState(defaultOpen);
246
+ const isControlled = controlledOpen !== void 0;
247
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
248
+ const triggerRef = React2.useRef(null);
249
+ const dialogId = React2.useId();
250
+ const handleOpenChange = React2.useCallback(
251
+ (newOpen) => {
252
+ if (!isControlled) {
253
+ setUncontrolledOpen(newOpen);
254
+ }
255
+ onOpenChange?.(newOpen);
256
+ },
257
+ [isControlled, onOpenChange]
258
+ );
259
+ return /* @__PURE__ */ jsx2(
260
+ DialogContext.Provider,
261
+ {
262
+ value: {
263
+ open: isOpen,
264
+ onOpenChange: handleOpenChange,
265
+ dialogId,
266
+ triggerRef
267
+ },
268
+ children
269
+ }
270
+ );
271
+ }
272
+ var DialogTrigger = React2.forwardRef(
273
+ ({ children, className, onClick, asChild = false, ...props }, ref) => {
274
+ const { open, onOpenChange, dialogId, triggerRef } = useDialogContext();
275
+ const setRef = React2.useCallback(
276
+ (node) => {
277
+ triggerRef.current = node;
278
+ if (typeof ref === "function") {
279
+ ref(node);
280
+ } else if (ref) {
281
+ ref.current = node;
282
+ }
283
+ },
284
+ [ref, triggerRef]
285
+ );
286
+ return /* @__PURE__ */ jsx2(
287
+ "button",
288
+ {
289
+ ref: setRef,
290
+ type: "button",
291
+ "aria-haspopup": "dialog",
292
+ "aria-expanded": open,
293
+ "aria-controls": dialogId,
294
+ "data-slot": "trigger",
295
+ className: cn("yc-Dialog-trigger", className),
296
+ onClick: (e) => {
297
+ onClick?.(e);
298
+ if (!e.defaultPrevented) {
299
+ onOpenChange(!open);
300
+ }
301
+ },
302
+ ...props,
303
+ children
304
+ }
305
+ );
306
+ }
307
+ );
308
+ DialogTrigger.displayName = "DialogTrigger";
309
+ var DialogContent = React2.forwardRef(
310
+ ({ children, className, ...props }, ref) => {
311
+ const { open, onOpenChange, dialogId, triggerRef } = useDialogContext();
312
+ const contentRef = React2.useRef(null);
313
+ React2.useEffect(() => {
314
+ if (!open) return;
315
+ const handleKeyDown = (e) => {
316
+ if (e.key === "Escape") {
317
+ e.stopPropagation();
318
+ onOpenChange(false);
319
+ triggerRef.current?.focus();
320
+ }
321
+ };
322
+ document.addEventListener("keydown", handleKeyDown);
323
+ return () => document.removeEventListener("keydown", handleKeyDown);
324
+ }, [open, onOpenChange, triggerRef]);
325
+ if (!open) return null;
326
+ return /* @__PURE__ */ jsxs2(
327
+ "div",
328
+ {
329
+ className: "yc-Dialog-portal fixed inset-0 z-50 flex items-center justify-center p-4",
330
+ "data-slot": "portal",
331
+ children: [
332
+ /* @__PURE__ */ jsx2(
333
+ "div",
334
+ {
335
+ className: "yc-Dialog-overlay fixed inset-0 bg-overlay transition-opacity",
336
+ "data-slot": "overlay",
337
+ onClick: () => onOpenChange(false),
338
+ "aria-hidden": "true"
339
+ }
340
+ ),
341
+ /* @__PURE__ */ jsx2(
342
+ "div",
343
+ {
344
+ ref: (node) => {
345
+ contentRef.current = node;
346
+ if (typeof ref === "function") ref(node);
347
+ else if (ref) ref.current = node;
348
+ },
349
+ id: dialogId,
350
+ role: "dialog",
351
+ "aria-modal": "true",
352
+ "data-slot": "content",
353
+ className: cn(
354
+ "yc-Dialog-content relative z-10 w-full max-w-lg rounded-xl bg-surface p-6 text-fg shadow-3 border border-border",
355
+ "focus:outline-none",
356
+ className
357
+ ),
358
+ ...props,
359
+ children
360
+ }
361
+ )
362
+ ]
363
+ }
364
+ );
365
+ }
366
+ );
367
+ DialogContent.displayName = "DialogContent";
368
+ var DialogHeader = ({
369
+ className,
370
+ ...props
371
+ }) => /* @__PURE__ */ jsx2(
372
+ "div",
373
+ {
374
+ className: cn("yc-Dialog-header flex flex-col space-y-1.5 text-start pb-4", className),
375
+ "data-slot": "header",
376
+ ...props
377
+ }
378
+ );
379
+ DialogHeader.displayName = "DialogHeader";
380
+ var DialogFooter = ({
381
+ className,
382
+ ...props
383
+ }) => /* @__PURE__ */ jsx2(
384
+ "div",
385
+ {
386
+ className: cn("yc-Dialog-footer flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", className),
387
+ "data-slot": "footer",
388
+ ...props
389
+ }
390
+ );
391
+ DialogFooter.displayName = "DialogFooter";
392
+ var DialogTitle = ({
393
+ className,
394
+ ...props
395
+ }) => /* @__PURE__ */ jsx2(
396
+ "h2",
397
+ {
398
+ className: cn("yc-Dialog-title text-lg font-semibold leading-none tracking-tight text-fg", className),
399
+ "data-slot": "title",
400
+ ...props
401
+ }
402
+ );
403
+ DialogTitle.displayName = "DialogTitle";
404
+ var DialogDescription = ({
405
+ className,
406
+ ...props
407
+ }) => /* @__PURE__ */ jsx2(
408
+ "p",
409
+ {
410
+ className: cn("yc-Dialog-description text-sm text-fg-muted", className),
411
+ "data-slot": "description",
412
+ ...props
413
+ }
414
+ );
415
+ DialogDescription.displayName = "DialogDescription";
416
+ var DialogClose = ({
417
+ className,
418
+ children,
419
+ onClick,
420
+ asChild = false,
421
+ ...props
422
+ }) => {
423
+ const { onOpenChange } = useDialogContext();
424
+ return /* @__PURE__ */ jsx2(
425
+ "button",
426
+ {
427
+ type: "button",
428
+ className: cn("yc-Dialog-close", className),
429
+ "data-slot": "close",
430
+ onClick: (e) => {
431
+ onClick?.(e);
432
+ if (!e.defaultPrevented) onOpenChange(false);
433
+ },
434
+ ...props,
435
+ children: children || "Close"
436
+ }
437
+ );
438
+ };
439
+ DialogClose.displayName = "DialogClose";
440
+
441
+ // src/primitives/Sheet.tsx
442
+ import * as React3 from "react";
443
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
444
+ var SheetContext = React3.createContext(null);
445
+ function useSheetContext() {
446
+ const context = React3.useContext(SheetContext);
447
+ if (!context) {
448
+ throw new Error("Sheet compound components must be rendered within a <Sheet>");
449
+ }
450
+ return context;
451
+ }
452
+ function Sheet({
453
+ open: controlledOpen,
454
+ defaultOpen = false,
455
+ onOpenChange,
456
+ side = "end",
457
+ children
458
+ }) {
459
+ const [uncontrolledOpen, setUncontrolledOpen] = React3.useState(defaultOpen);
460
+ const isControlled = controlledOpen !== void 0;
461
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
462
+ const triggerRef = React3.useRef(null);
463
+ const sheetId = React3.useId();
464
+ const handleOpenChange = React3.useCallback(
465
+ (newOpen) => {
466
+ if (!isControlled) {
467
+ setUncontrolledOpen(newOpen);
468
+ }
469
+ onOpenChange?.(newOpen);
470
+ },
471
+ [isControlled, onOpenChange]
472
+ );
473
+ return /* @__PURE__ */ jsx3(
474
+ SheetContext.Provider,
475
+ {
476
+ value: {
477
+ open: isOpen,
478
+ onOpenChange: handleOpenChange,
479
+ side,
480
+ sheetId,
481
+ triggerRef
482
+ },
483
+ children
484
+ }
485
+ );
486
+ }
487
+ var SheetTrigger = React3.forwardRef(
488
+ ({ children, className, onClick, asChild = false, ...props }, ref) => {
489
+ const { open, onOpenChange, sheetId, triggerRef } = useSheetContext();
490
+ return /* @__PURE__ */ jsx3(
491
+ "button",
492
+ {
493
+ ref: (node) => {
494
+ triggerRef.current = node;
495
+ if (typeof ref === "function") ref(node);
496
+ else if (ref) ref.current = node;
497
+ },
498
+ type: "button",
499
+ "aria-haspopup": "dialog",
500
+ "aria-expanded": open,
501
+ "aria-controls": sheetId,
502
+ "data-slot": "trigger",
503
+ className: cn("yc-Sheet-trigger", className),
504
+ onClick: (e) => {
505
+ onClick?.(e);
506
+ if (!e.defaultPrevented) onOpenChange(!open);
507
+ },
508
+ ...props,
509
+ children
510
+ }
511
+ );
512
+ }
513
+ );
514
+ SheetTrigger.displayName = "SheetTrigger";
515
+ var sideStyles = {
516
+ end: "inset-y-0 end-0 h-full w-3/4 max-w-md border-s border-border",
517
+ start: "inset-y-0 start-0 h-full w-3/4 max-w-md border-e border-border",
518
+ bottom: "inset-x-0 bottom-0 max-h-[85vh] border-t border-border rounded-t-xl"
519
+ };
520
+ var SheetContent = React3.forwardRef(
521
+ ({ children, className, side: propSide, ...props }, ref) => {
522
+ const { open, onOpenChange, side: contextSide, sheetId, triggerRef } = useSheetContext();
523
+ const side = propSide || contextSide;
524
+ React3.useEffect(() => {
525
+ if (!open) return;
526
+ const handleKeyDown = (e) => {
527
+ if (e.key === "Escape") {
528
+ e.stopPropagation();
529
+ onOpenChange(false);
530
+ triggerRef.current?.focus();
531
+ }
532
+ };
533
+ document.addEventListener("keydown", handleKeyDown);
534
+ return () => document.removeEventListener("keydown", handleKeyDown);
535
+ }, [open, onOpenChange, triggerRef]);
536
+ if (!open) return null;
537
+ return /* @__PURE__ */ jsxs3("div", { className: "yc-Sheet-portal fixed inset-0 z-50 flex", "data-slot": "portal", children: [
538
+ /* @__PURE__ */ jsx3(
539
+ "div",
540
+ {
541
+ className: "yc-Sheet-overlay fixed inset-0 bg-overlay transition-opacity",
542
+ "data-slot": "overlay",
543
+ onClick: () => onOpenChange(false),
544
+ "aria-hidden": "true"
545
+ }
546
+ ),
547
+ /* @__PURE__ */ jsx3(
548
+ "div",
549
+ {
550
+ ref,
551
+ id: sheetId,
552
+ role: "dialog",
553
+ "aria-modal": "true",
554
+ "data-slot": "content",
555
+ "data-side": side,
556
+ className: cn(
557
+ "yc-Sheet-content fixed z-10 bg-surface p-6 shadow-3 text-fg transition-transform",
558
+ sideStyles[side],
559
+ className
560
+ ),
561
+ ...props,
562
+ children
563
+ }
564
+ )
565
+ ] });
566
+ }
567
+ );
568
+ SheetContent.displayName = "SheetContent";
569
+ var SheetHeader = ({
570
+ className,
571
+ ...props
572
+ }) => /* @__PURE__ */ jsx3(
573
+ "div",
574
+ {
575
+ className: cn("yc-Sheet-header flex flex-col space-y-2 text-start pb-4", className),
576
+ "data-slot": "header",
577
+ ...props
578
+ }
579
+ );
580
+ SheetHeader.displayName = "SheetHeader";
581
+ var SheetFooter = ({
582
+ className,
583
+ ...props
584
+ }) => /* @__PURE__ */ jsx3(
585
+ "div",
586
+ {
587
+ className: cn("yc-Sheet-footer flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", className),
588
+ "data-slot": "footer",
589
+ ...props
590
+ }
591
+ );
592
+ SheetFooter.displayName = "SheetFooter";
593
+ var SheetTitle = ({
594
+ className,
595
+ ...props
596
+ }) => /* @__PURE__ */ jsx3(
597
+ "h2",
598
+ {
599
+ className: cn("yc-Sheet-title text-lg font-semibold text-fg", className),
600
+ "data-slot": "title",
601
+ ...props
602
+ }
603
+ );
604
+ SheetTitle.displayName = "SheetTitle";
605
+ var SheetDescription = ({
606
+ className,
607
+ ...props
608
+ }) => /* @__PURE__ */ jsx3(
609
+ "p",
610
+ {
611
+ className: cn("yc-Sheet-description text-sm text-fg-muted", className),
612
+ "data-slot": "description",
613
+ ...props
614
+ }
615
+ );
616
+ SheetDescription.displayName = "SheetDescription";
617
+ var SheetClose = ({
618
+ className,
619
+ children,
620
+ onClick,
621
+ ...props
622
+ }) => {
623
+ const { onOpenChange } = useSheetContext();
624
+ return /* @__PURE__ */ jsx3(
625
+ "button",
626
+ {
627
+ type: "button",
628
+ className: cn("yc-Sheet-close", className),
629
+ "data-slot": "close",
630
+ onClick: (e) => {
631
+ onClick?.(e);
632
+ if (!e.defaultPrevented) onOpenChange(false);
633
+ },
634
+ ...props,
635
+ children: children || "Close"
636
+ }
637
+ );
638
+ };
639
+ SheetClose.displayName = "SheetClose";
640
+
641
+ // src/primitives/Card.tsx
642
+ import * as React4 from "react";
643
+ import { jsx as jsx4 } from "react/jsx-runtime";
644
+ var Card = React4.forwardRef(
645
+ ({ className, variant = "default", ...props }, ref) => /* @__PURE__ */ jsx4(
646
+ "div",
647
+ {
648
+ ref,
649
+ "data-slot": "card",
650
+ "data-variant": variant,
651
+ className: cn(
652
+ "yc-Card-root rounded-lg border border-border bg-surface text-fg shadow-1",
653
+ variant === "muted" && "bg-surface-2",
654
+ variant === "interactive" && "hover:border-border-strong hover:bg-surface-2 transition-colors duration-fast cursor-pointer",
655
+ className
656
+ ),
657
+ ...props
658
+ }
659
+ )
660
+ );
661
+ Card.displayName = "Card";
662
+ var CardHeader = React4.forwardRef(
663
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
664
+ "div",
665
+ {
666
+ ref,
667
+ "data-slot": "header",
668
+ className: cn("yc-Card-header flex flex-col space-y-1.5 p-6 text-start", className),
669
+ ...props
670
+ }
671
+ )
672
+ );
673
+ CardHeader.displayName = "CardHeader";
674
+ var CardTitle = React4.forwardRef(
675
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
676
+ "h3",
677
+ {
678
+ ref,
679
+ "data-slot": "title",
680
+ className: cn("yc-Card-title text-lg font-semibold leading-none tracking-tight text-fg", className),
681
+ ...props
682
+ }
683
+ )
684
+ );
685
+ CardTitle.displayName = "CardTitle";
686
+ var CardDescription = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
687
+ "p",
688
+ {
689
+ ref,
690
+ "data-slot": "description",
691
+ className: cn("yc-Card-description text-sm text-fg-muted", className),
692
+ ...props
693
+ }
694
+ ));
695
+ CardDescription.displayName = "CardDescription";
696
+ var CardContent = React4.forwardRef(
697
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx4("div", { ref, "data-slot": "content", className: cn("yc-Card-content p-6 pt-0 text-start", className), ...props })
698
+ );
699
+ CardContent.displayName = "CardContent";
700
+ var CardFooter = React4.forwardRef(
701
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
702
+ "div",
703
+ {
704
+ ref,
705
+ "data-slot": "footer",
706
+ className: cn("yc-Card-footer flex items-center p-6 pt-0", className),
707
+ ...props
708
+ }
709
+ )
710
+ );
711
+ CardFooter.displayName = "CardFooter";
712
+
713
+ // src/primitives/Badge.tsx
714
+ import { jsx as jsx5 } from "react/jsx-runtime";
715
+ var variantStyles2 = {
716
+ default: "bg-primary-soft text-primary-soft-fg border-transparent",
717
+ primary: "bg-primary text-primary-fg border-transparent",
718
+ neutral: "bg-surface-2 text-fg-muted border-border",
719
+ info: "bg-info-bg text-info-fg border-info-border",
720
+ warn: "bg-warn-bg text-warn-fg border-warn-border",
721
+ danger: "bg-danger-bg text-danger-fg border-danger-border",
722
+ success: "bg-success-bg text-success-fg border-success-border",
723
+ outline: "bg-transparent text-fg border-border-strong"
724
+ };
725
+ var Badge = ({
726
+ className,
727
+ variant = "default",
728
+ children,
729
+ ...props
730
+ }) => {
731
+ return /* @__PURE__ */ jsx5(
732
+ "span",
733
+ {
734
+ "data-slot": "badge",
735
+ "data-variant": variant,
736
+ className: cn(
737
+ "yc-Badge-root inline-flex items-center rounded-sm border px-2.5 py-0.5 text-xs font-medium transition-colors",
738
+ variantStyles2[variant],
739
+ className
740
+ ),
741
+ ...props,
742
+ children
743
+ }
744
+ );
745
+ };
746
+ Badge.displayName = "Badge";
747
+
748
+ // src/primitives/Avatar.tsx
749
+ import * as React5 from "react";
750
+ import { jsx as jsx6 } from "react/jsx-runtime";
751
+ var sizeStyles2 = {
752
+ sm: "h-8 w-8 text-xs",
753
+ md: "h-10 w-10 text-sm",
754
+ lg: "h-12 w-12 text-base",
755
+ xl: "h-16 w-16 text-lg"
756
+ };
757
+ var memberColorStyles = {
758
+ "1": "bg-member-1-bg text-member-1-fg",
759
+ "2": "bg-member-2-bg text-member-2-fg",
760
+ "3": "bg-member-3-bg text-member-3-fg",
761
+ "4": "bg-member-4-bg text-member-4-fg",
762
+ "5": "bg-member-5-bg text-member-5-fg"
763
+ };
764
+ var Avatar = ({
765
+ src,
766
+ alt = "",
767
+ name,
768
+ size = "md",
769
+ colorSlot = "1",
770
+ children,
771
+ className,
772
+ ...props
773
+ }) => {
774
+ const [hasError, setHasError] = React5.useState(false);
775
+ const initials = React5.useMemo(() => {
776
+ if (!name) return "?";
777
+ const parts = name.trim().split(/\s+/);
778
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
779
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
780
+ }, [name]);
781
+ const showImage = src && !hasError;
782
+ return /* @__PURE__ */ jsx6(
783
+ "div",
784
+ {
785
+ "data-slot": "avatar",
786
+ "data-size": size,
787
+ "data-color-slot": colorSlot,
788
+ className: cn(
789
+ "yc-Avatar-root relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full font-medium select-none border border-border",
790
+ sizeStyles2[size],
791
+ memberColorStyles[colorSlot],
792
+ className
793
+ ),
794
+ ...props,
795
+ children: children ? children : showImage ? /* @__PURE__ */ jsx6(
796
+ "img",
797
+ {
798
+ src,
799
+ alt: alt || name || "Avatar",
800
+ onError: () => setHasError(true),
801
+ "data-slot": "avatar-image",
802
+ className: "yc-Avatar-image h-full w-full object-cover"
803
+ }
804
+ ) : /* @__PURE__ */ jsx6("span", { "data-slot": "avatar-fallback", className: "yc-Avatar-fallback leading-none", children: initials })
805
+ }
806
+ );
807
+ };
808
+ Avatar.displayName = "Avatar";
809
+ var AvatarImage = ({ className, alt = "", ...props }) => /* @__PURE__ */ jsx6(
810
+ "img",
811
+ {
812
+ "data-slot": "avatar-image",
813
+ alt,
814
+ className: cn("yc-Avatar-image h-full w-full object-cover", className),
815
+ ...props
816
+ }
817
+ );
818
+ AvatarImage.displayName = "AvatarImage";
819
+ var AvatarFallback = ({ className, children, ...props }) => /* @__PURE__ */ jsx6(
820
+ "span",
821
+ {
822
+ "data-slot": "avatar-fallback",
823
+ className: cn("yc-Avatar-fallback leading-none font-medium", className),
824
+ ...props,
825
+ children
826
+ }
827
+ );
828
+ AvatarFallback.displayName = "AvatarFallback";
829
+
830
+ // src/primitives/Chip.tsx
831
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
832
+ var scopeStyles = {
833
+ default: {
834
+ default: "bg-surface text-fg border-border hover:bg-surface-2",
835
+ selected: "bg-primary text-primary-fg border-primary"
836
+ },
837
+ health: {
838
+ default: "bg-scope-health-bg text-scope-health-fg border-transparent hover:opacity-90",
839
+ selected: "bg-primary text-primary-fg border-primary"
840
+ },
841
+ finance: {
842
+ default: "bg-scope-finance-bg text-scope-finance-fg border-transparent hover:opacity-90",
843
+ selected: "bg-primary text-primary-fg border-primary"
844
+ },
845
+ education: {
846
+ default: "bg-scope-education-bg text-scope-education-fg border-transparent hover:opacity-90",
847
+ selected: "bg-primary text-primary-fg border-primary"
848
+ },
849
+ household: {
850
+ default: "bg-scope-household-bg text-scope-household-fg border-transparent hover:opacity-90",
851
+ selected: "bg-primary text-primary-fg border-primary"
852
+ }
853
+ };
854
+ var Chip = ({
855
+ children,
856
+ selected = false,
857
+ scope = "default",
858
+ onRemove,
859
+ startIcon,
860
+ className,
861
+ onClick,
862
+ disabled = false,
863
+ ...props
864
+ }) => {
865
+ return /* @__PURE__ */ jsxs4(
866
+ "button",
867
+ {
868
+ type: "button",
869
+ "data-slot": "chip",
870
+ "data-selected": selected ? "true" : void 0,
871
+ "data-scope": scope,
872
+ disabled,
873
+ onClick,
874
+ className: cn(
875
+ "yc-Chip-root inline-flex items-center rounded-sm border px-3 py-1 text-xs font-medium transition-colors select-none",
876
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus",
877
+ "disabled:opacity-50 disabled:cursor-not-allowed",
878
+ selected ? scopeStyles[scope].selected : scopeStyles[scope].default,
879
+ className
880
+ ),
881
+ ...props,
882
+ children: [
883
+ startIcon && /* @__PURE__ */ jsx7("span", { className: "yc-Chip-icon me-1.5 inline-flex shrink-0 items-center", "data-slot": "icon", children: startIcon }),
884
+ /* @__PURE__ */ jsx7("span", { className: "yc-Chip-label truncate", "data-slot": "label", children }),
885
+ onRemove && /* @__PURE__ */ jsx7(
886
+ "span",
887
+ {
888
+ role: "button",
889
+ tabIndex: 0,
890
+ "aria-label": "Remove",
891
+ "data-slot": "remove",
892
+ onClick: (e) => {
893
+ e.stopPropagation();
894
+ onRemove();
895
+ },
896
+ className: "yc-Chip-remove ms-1.5 inline-flex items-center justify-center rounded-full p-0.5 hover:bg-black/10 focus:outline-none",
897
+ children: /* @__PURE__ */ jsx7("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx7("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
898
+ }
899
+ )
900
+ ]
901
+ }
902
+ );
903
+ };
904
+ Chip.displayName = "Chip";
905
+
906
+ // src/primitives/Menu.tsx
907
+ import * as React6 from "react";
908
+ import { jsx as jsx8 } from "react/jsx-runtime";
909
+ var MenuContext = React6.createContext(null);
910
+ function useMenuContext() {
911
+ const ctx = React6.useContext(MenuContext);
912
+ if (!ctx) throw new Error("Menu compound components must be rendered inside <Menu>");
913
+ return ctx;
914
+ }
915
+ function Menu({ open: controlledOpen, defaultOpen = false, onOpenChange, children }) {
916
+ const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(defaultOpen);
917
+ const isControlled = controlledOpen !== void 0;
918
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
919
+ const triggerRef = React6.useRef(null);
920
+ const menuId = React6.useId();
921
+ const setOpen = React6.useCallback(
922
+ (next) => {
923
+ if (!isControlled) setUncontrolledOpen(next);
924
+ onOpenChange?.(next);
925
+ },
926
+ [isControlled, onOpenChange]
927
+ );
928
+ return /* @__PURE__ */ jsx8(MenuContext.Provider, { value: { open: isOpen, setOpen, triggerRef, menuId }, children: /* @__PURE__ */ jsx8("div", { className: "yc-Menu-root relative inline-block text-start", "data-slot": "root", children }) });
929
+ }
930
+ var MenuTrigger = React6.forwardRef(
931
+ ({ children, className, onClick, ...props }, ref) => {
932
+ const { open, setOpen, menuId, triggerRef } = useMenuContext();
933
+ return /* @__PURE__ */ jsx8(
934
+ "button",
935
+ {
936
+ ref: (node) => {
937
+ triggerRef.current = node;
938
+ if (typeof ref === "function") ref(node);
939
+ else if (ref) ref.current = node;
940
+ },
941
+ type: "button",
942
+ "aria-haspopup": "menu",
943
+ "aria-expanded": open,
944
+ "aria-controls": menuId,
945
+ "data-slot": "trigger",
946
+ className: cn("yc-Menu-trigger inline-flex items-center justify-center", className),
947
+ onClick: (e) => {
948
+ onClick?.(e);
949
+ if (!e.defaultPrevented) setOpen(!open);
950
+ },
951
+ ...props,
952
+ children
953
+ }
954
+ );
955
+ }
956
+ );
957
+ MenuTrigger.displayName = "MenuTrigger";
958
+ var MenuContent = React6.forwardRef(
959
+ ({ children, className, align = "start", ...props }, ref) => {
960
+ const { open, setOpen, menuId, triggerRef } = useMenuContext();
961
+ const contentRef = React6.useRef(null);
962
+ React6.useEffect(() => {
963
+ if (!open) return;
964
+ const handleClickOutside = (e) => {
965
+ if (contentRef.current && !contentRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
966
+ setOpen(false);
967
+ }
968
+ };
969
+ const handleKeyDown = (e) => {
970
+ if (e.key === "Escape") {
971
+ e.stopPropagation();
972
+ setOpen(false);
973
+ triggerRef.current?.focus();
974
+ }
975
+ };
976
+ document.addEventListener("mousedown", handleClickOutside);
977
+ document.addEventListener("keydown", handleKeyDown);
978
+ return () => {
979
+ document.removeEventListener("mousedown", handleClickOutside);
980
+ document.removeEventListener("keydown", handleKeyDown);
981
+ };
982
+ }, [open, setOpen, triggerRef]);
983
+ if (!open) return null;
984
+ const alignClass = align === "end" ? "end-0" : align === "center" ? "start-1/2 -translate-x-1/2" : "start-0";
985
+ return /* @__PURE__ */ jsx8(
986
+ "div",
987
+ {
988
+ ref: (node) => {
989
+ contentRef.current = node;
990
+ if (typeof ref === "function") ref(node);
991
+ else if (ref) ref.current = node;
992
+ },
993
+ id: menuId,
994
+ role: "menu",
995
+ "aria-orientation": "vertical",
996
+ tabIndex: -1,
997
+ "data-slot": "content",
998
+ className: cn(
999
+ "yc-Menu-content absolute z-50 mt-1 min-w-[12rem] rounded-md bg-surface p-1 text-fg shadow-2 border border-border focus:outline-none",
1000
+ alignClass,
1001
+ className
1002
+ ),
1003
+ ...props,
1004
+ children
1005
+ }
1006
+ );
1007
+ }
1008
+ );
1009
+ MenuContent.displayName = "MenuContent";
1010
+ var MenuItem = React6.forwardRef(
1011
+ ({ children, className, destructive = false, onClick, disabled = false, ...props }, ref) => {
1012
+ const { setOpen } = useMenuContext();
1013
+ return /* @__PURE__ */ jsx8(
1014
+ "button",
1015
+ {
1016
+ ref,
1017
+ type: "button",
1018
+ role: "menuitem",
1019
+ tabIndex: -1,
1020
+ disabled,
1021
+ "data-slot": "item",
1022
+ "data-destructive": destructive ? "true" : void 0,
1023
+ className: cn(
1024
+ "yc-Menu-item group relative flex w-full cursor-pointer select-none items-center rounded-sm px-2.5 py-1.5 text-sm outline-none transition-colors duration-fast",
1025
+ "hover:bg-surface-2 focus:bg-surface-2",
1026
+ destructive ? "text-danger-fg hover:bg-danger-bg focus:bg-danger-bg" : "text-fg hover:text-fg",
1027
+ "disabled:pointer-events-none disabled:opacity-50",
1028
+ className
1029
+ ),
1030
+ onClick: (e) => {
1031
+ onClick?.(e);
1032
+ if (!e.defaultPrevented) setOpen(false);
1033
+ },
1034
+ ...props,
1035
+ children
1036
+ }
1037
+ );
1038
+ }
1039
+ );
1040
+ MenuItem.displayName = "MenuItem";
1041
+ var MenuSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx8(
1042
+ "div",
1043
+ {
1044
+ role: "separator",
1045
+ "data-slot": "separator",
1046
+ className: cn("yc-Menu-separator my-1 h-px bg-border", className),
1047
+ ...props
1048
+ }
1049
+ );
1050
+ MenuSeparator.displayName = "MenuSeparator";
1051
+
1052
+ // src/primitives/Popover.tsx
1053
+ import * as React7 from "react";
1054
+ import { jsx as jsx9 } from "react/jsx-runtime";
1055
+ var PopoverContext = React7.createContext(null);
1056
+ function usePopoverContext() {
1057
+ const ctx = React7.useContext(PopoverContext);
1058
+ if (!ctx) throw new Error("Popover compound components must be rendered inside <Popover>");
1059
+ return ctx;
1060
+ }
1061
+ function Popover({ open: controlledOpen, defaultOpen = false, onOpenChange, children }) {
1062
+ const [uncontrolledOpen, setUncontrolledOpen] = React7.useState(defaultOpen);
1063
+ const isControlled = controlledOpen !== void 0;
1064
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
1065
+ const triggerRef = React7.useRef(null);
1066
+ const popoverId = React7.useId();
1067
+ const setOpen = React7.useCallback(
1068
+ (next) => {
1069
+ if (!isControlled) setUncontrolledOpen(next);
1070
+ onOpenChange?.(next);
1071
+ },
1072
+ [isControlled, onOpenChange]
1073
+ );
1074
+ return /* @__PURE__ */ jsx9(PopoverContext.Provider, { value: { open: isOpen, setOpen, triggerRef, popoverId }, children: /* @__PURE__ */ jsx9("div", { className: "yc-Popover-root relative inline-block text-start", "data-slot": "root", children }) });
1075
+ }
1076
+ var PopoverTrigger = React7.forwardRef(
1077
+ ({ children, className, onClick, ...props }, ref) => {
1078
+ const { open, setOpen, popoverId, triggerRef } = usePopoverContext();
1079
+ return /* @__PURE__ */ jsx9(
1080
+ "button",
1081
+ {
1082
+ ref: (node) => {
1083
+ triggerRef.current = node;
1084
+ if (typeof ref === "function") ref(node);
1085
+ else if (ref) ref.current = node;
1086
+ },
1087
+ type: "button",
1088
+ "aria-haspopup": "dialog",
1089
+ "aria-expanded": open,
1090
+ "aria-controls": popoverId,
1091
+ "data-slot": "trigger",
1092
+ className: cn("yc-Popover-trigger inline-flex items-center justify-center", className),
1093
+ onClick: (e) => {
1094
+ onClick?.(e);
1095
+ if (!e.defaultPrevented) setOpen(!open);
1096
+ },
1097
+ ...props,
1098
+ children
1099
+ }
1100
+ );
1101
+ }
1102
+ );
1103
+ PopoverTrigger.displayName = "PopoverTrigger";
1104
+ var PopoverContent = React7.forwardRef(
1105
+ ({ children, className, align = "start", ...props }, ref) => {
1106
+ const { open, setOpen, popoverId, triggerRef } = usePopoverContext();
1107
+ const contentRef = React7.useRef(null);
1108
+ React7.useEffect(() => {
1109
+ if (!open) return;
1110
+ const handleClickOutside = (e) => {
1111
+ if (contentRef.current && !contentRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
1112
+ setOpen(false);
1113
+ }
1114
+ };
1115
+ const handleKeyDown = (e) => {
1116
+ if (e.key === "Escape") {
1117
+ e.stopPropagation();
1118
+ setOpen(false);
1119
+ triggerRef.current?.focus();
1120
+ }
1121
+ };
1122
+ document.addEventListener("mousedown", handleClickOutside);
1123
+ document.addEventListener("keydown", handleKeyDown);
1124
+ return () => {
1125
+ document.removeEventListener("mousedown", handleClickOutside);
1126
+ document.removeEventListener("keydown", handleKeyDown);
1127
+ };
1128
+ }, [open, setOpen, triggerRef]);
1129
+ if (!open) return null;
1130
+ const alignClass = align === "end" ? "end-0" : align === "center" ? "start-1/2 -translate-x-1/2" : "start-0";
1131
+ return /* @__PURE__ */ jsx9(
1132
+ "div",
1133
+ {
1134
+ ref: (node) => {
1135
+ contentRef.current = node;
1136
+ if (typeof ref === "function") ref(node);
1137
+ else if (ref) ref.current = node;
1138
+ },
1139
+ id: popoverId,
1140
+ role: "dialog",
1141
+ "data-slot": "content",
1142
+ className: cn(
1143
+ "yc-Popover-content absolute z-50 mt-1 min-w-[14rem] rounded-lg bg-surface p-4 text-fg shadow-2 border border-border focus:outline-none",
1144
+ alignClass,
1145
+ className
1146
+ ),
1147
+ ...props,
1148
+ children
1149
+ }
1150
+ );
1151
+ }
1152
+ );
1153
+ PopoverContent.displayName = "PopoverContent";
1154
+
1155
+ // src/primitives/Tabs.tsx
1156
+ import * as React8 from "react";
1157
+ import { jsx as jsx10 } from "react/jsx-runtime";
1158
+ var TabsContext = React8.createContext(null);
1159
+ function useTabsContext() {
1160
+ const ctx = React8.useContext(TabsContext);
1161
+ if (!ctx) throw new Error("Tabs compound components must be rendered inside <Tabs>");
1162
+ return ctx;
1163
+ }
1164
+ function Tabs({
1165
+ value: controlledValue,
1166
+ defaultValue = "",
1167
+ onValueChange,
1168
+ children,
1169
+ className,
1170
+ ...props
1171
+ }) {
1172
+ const [uncontrolledValue, setUncontrolledValue] = React8.useState(defaultValue);
1173
+ const isControlled = controlledValue !== void 0;
1174
+ const activeValue = isControlled ? controlledValue : uncontrolledValue;
1175
+ const baseId = React8.useId();
1176
+ const handleValueChange = React8.useCallback(
1177
+ (newVal) => {
1178
+ if (!isControlled) setUncontrolledValue(newVal);
1179
+ onValueChange?.(newVal);
1180
+ },
1181
+ [isControlled, onValueChange]
1182
+ );
1183
+ return /* @__PURE__ */ jsx10(TabsContext.Provider, { value: { value: activeValue, onValueChange: handleValueChange, baseId }, children: /* @__PURE__ */ jsx10("div", { className: cn("yc-Tabs-root flex flex-col", className), "data-slot": "root", ...props, children }) });
1184
+ }
1185
+ var TabsList = React8.forwardRef(
1186
+ ({ children, className, ...props }, ref) => {
1187
+ return /* @__PURE__ */ jsx10(
1188
+ "div",
1189
+ {
1190
+ ref,
1191
+ role: "tablist",
1192
+ "data-slot": "list",
1193
+ className: cn(
1194
+ "yc-Tabs-list inline-flex h-10 items-center justify-start rounded-lg bg-surface-2 p-1 text-fg-muted",
1195
+ className
1196
+ ),
1197
+ ...props,
1198
+ children
1199
+ }
1200
+ );
1201
+ }
1202
+ );
1203
+ TabsList.displayName = "TabsList";
1204
+ var TabsTrigger = React8.forwardRef(
1205
+ ({ value, children, className, disabled = false, ...props }, ref) => {
1206
+ const { value: activeValue, onValueChange, baseId } = useTabsContext();
1207
+ const isSelected = activeValue === value;
1208
+ const tabId = `${baseId}-tab-${value}`;
1209
+ const panelId = `${baseId}-panel-${value}`;
1210
+ return /* @__PURE__ */ jsx10(
1211
+ "button",
1212
+ {
1213
+ ref,
1214
+ id: tabId,
1215
+ type: "button",
1216
+ role: "tab",
1217
+ "aria-selected": isSelected,
1218
+ "aria-controls": panelId,
1219
+ tabIndex: isSelected ? 0 : -1,
1220
+ disabled,
1221
+ "data-slot": "trigger",
1222
+ "data-state": isSelected ? "active" : "inactive",
1223
+ className: cn(
1224
+ "yc-Tabs-trigger inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium transition-all duration-fast",
1225
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2",
1226
+ "disabled:pointer-events-none disabled:opacity-50",
1227
+ isSelected ? "bg-surface text-fg shadow-1" : "text-fg-muted hover:text-fg hover:bg-surface-3",
1228
+ className
1229
+ ),
1230
+ onClick: () => onValueChange(value),
1231
+ ...props,
1232
+ children
1233
+ }
1234
+ );
1235
+ }
1236
+ );
1237
+ TabsTrigger.displayName = "TabsTrigger";
1238
+ var TabsContent = React8.forwardRef(
1239
+ ({ value, children, className, ...props }, ref) => {
1240
+ const { value: activeValue, baseId } = useTabsContext();
1241
+ const isSelected = activeValue === value;
1242
+ const tabId = `${baseId}-tab-${value}`;
1243
+ const panelId = `${baseId}-panel-${value}`;
1244
+ if (!isSelected) return null;
1245
+ return /* @__PURE__ */ jsx10(
1246
+ "div",
1247
+ {
1248
+ ref,
1249
+ id: panelId,
1250
+ role: "tabpanel",
1251
+ "aria-labelledby": tabId,
1252
+ tabIndex: 0,
1253
+ "data-slot": "content",
1254
+ className: cn(
1255
+ "yc-Tabs-content mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2",
1256
+ className
1257
+ ),
1258
+ ...props,
1259
+ children
1260
+ }
1261
+ );
1262
+ }
1263
+ );
1264
+ TabsContent.displayName = "TabsContent";
1265
+
1266
+ // src/primitives/Segmented.tsx
1267
+ import * as React9 from "react";
1268
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
1269
+ function SegmentedControl({
1270
+ options,
1271
+ value: controlledValue,
1272
+ defaultValue,
1273
+ onChange,
1274
+ className,
1275
+ size = "md"
1276
+ }) {
1277
+ const [uncontrolledValue, setUncontrolledValue] = React9.useState(
1278
+ defaultValue || (options.length > 0 ? options[0].value : "")
1279
+ );
1280
+ const isControlled = controlledValue !== void 0;
1281
+ const activeValue = isControlled ? controlledValue : uncontrolledValue;
1282
+ const handleClick = (optValue) => {
1283
+ if (!isControlled) {
1284
+ setUncontrolledValue(optValue);
1285
+ }
1286
+ onChange?.(optValue);
1287
+ };
1288
+ const sizeClasses = size === "sm" ? "h-8 p-0.5 text-xs" : "min-h-[44px] h-10 p-1 text-sm";
1289
+ return /* @__PURE__ */ jsx11(
1290
+ "div",
1291
+ {
1292
+ role: "radiogroup",
1293
+ "data-slot": "segmented-control",
1294
+ "data-size": size,
1295
+ className: cn(
1296
+ "yc-Segmented-root inline-flex items-center rounded-lg bg-surface-2 text-fg-muted border border-border select-none",
1297
+ sizeClasses,
1298
+ className
1299
+ ),
1300
+ children: options.map((opt) => {
1301
+ const isSelected = opt.value === activeValue;
1302
+ return /* @__PURE__ */ jsxs5(
1303
+ "button",
1304
+ {
1305
+ type: "button",
1306
+ role: "radio",
1307
+ "aria-checked": isSelected,
1308
+ disabled: opt.disabled,
1309
+ "data-slot": "item",
1310
+ "data-state": isSelected ? "checked" : "unchecked",
1311
+ onClick: () => handleClick(opt.value),
1312
+ className: cn(
1313
+ "yc-Segmented-item inline-flex h-full items-center justify-center gap-1.5 rounded-md px-3 font-medium transition-all duration-fast",
1314
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus",
1315
+ "disabled:pointer-events-none disabled:opacity-50",
1316
+ isSelected ? "bg-surface text-fg shadow-1" : "text-fg-muted hover:text-fg hover:bg-surface-3"
1317
+ ),
1318
+ children: [
1319
+ opt.icon && /* @__PURE__ */ jsx11("span", { className: "yc-Segmented-icon inline-flex shrink-0 items-center", "data-slot": "icon", children: opt.icon }),
1320
+ /* @__PURE__ */ jsx11("span", { className: "yc-Segmented-label truncate", "data-slot": "label", children: opt.label })
1321
+ ]
1322
+ },
1323
+ opt.value
1324
+ );
1325
+ })
1326
+ }
1327
+ );
1328
+ }
1329
+
1330
+ // src/primitives/EmptyState.tsx
1331
+ import * as React10 from "react";
1332
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
1333
+ var EmptyState = React10.forwardRef(
1334
+ ({ icon, title, description, action, className, ...props }, ref) => {
1335
+ return /* @__PURE__ */ jsxs6(
1336
+ "div",
1337
+ {
1338
+ ref,
1339
+ "data-slot": "empty-state",
1340
+ className: cn(
1341
+ "yc-EmptyState-root flex flex-col items-center justify-center p-8 text-center",
1342
+ className
1343
+ ),
1344
+ ...props,
1345
+ children: [
1346
+ icon && /* @__PURE__ */ jsx12(
1347
+ "div",
1348
+ {
1349
+ className: "yc-EmptyState-icon mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-surface-2 text-fg-muted",
1350
+ "data-slot": "icon",
1351
+ children: icon
1352
+ }
1353
+ ),
1354
+ /* @__PURE__ */ jsx12("h3", { className: "yc-EmptyState-title text-base font-medium text-fg", "data-slot": "title", children: title }),
1355
+ description && /* @__PURE__ */ jsx12(
1356
+ "p",
1357
+ {
1358
+ className: "yc-EmptyState-description mt-1.5 max-w-sm text-sm text-fg-muted",
1359
+ "data-slot": "description",
1360
+ children: description
1361
+ }
1362
+ ),
1363
+ action && /* @__PURE__ */ jsx12("div", { className: "yc-EmptyState-action mt-5", "data-slot": "action", children: action })
1364
+ ]
1365
+ }
1366
+ );
1367
+ }
1368
+ );
1369
+ EmptyState.displayName = "EmptyState";
1370
+
1371
+ // src/primitives/Skeleton.tsx
1372
+ import * as React11 from "react";
1373
+ import { jsx as jsx13 } from "react/jsx-runtime";
1374
+ var Skeleton = React11.forwardRef(
1375
+ ({ className, ...props }, ref) => {
1376
+ return /* @__PURE__ */ jsx13(
1377
+ "div",
1378
+ {
1379
+ ref,
1380
+ "data-slot": "skeleton",
1381
+ className: cn("yc-Skeleton-root animate-pulse rounded-md bg-surface-3", className),
1382
+ ...props
1383
+ }
1384
+ );
1385
+ }
1386
+ );
1387
+ Skeleton.displayName = "Skeleton";
1388
+
1389
+ // src/primitives/InlineError.tsx
1390
+ import * as React12 from "react";
1391
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
1392
+ var InlineError = React12.forwardRef(
1393
+ ({ message, icon, children, className, ...props }, ref) => {
1394
+ const content = message || children;
1395
+ if (!content) return null;
1396
+ return /* @__PURE__ */ jsxs7(
1397
+ "div",
1398
+ {
1399
+ ref,
1400
+ role: "alert",
1401
+ "data-slot": "inline-error",
1402
+ className: cn(
1403
+ "yc-InlineError-root flex items-center gap-1.5 text-xs font-medium text-danger-fg",
1404
+ className
1405
+ ),
1406
+ ...props,
1407
+ children: [
1408
+ icon && /* @__PURE__ */ jsx14("span", { className: "yc-InlineError-icon inline-flex shrink-0 items-center", "data-slot": "icon", children: icon }),
1409
+ /* @__PURE__ */ jsx14("span", { className: "yc-InlineError-message", "data-slot": "message", children: content })
1410
+ ]
1411
+ }
1412
+ );
1413
+ }
1414
+ );
1415
+ InlineError.displayName = "InlineError";
1416
+
1417
+ // src/primitives/Toaster.tsx
1418
+ import * as React13 from "react";
1419
+ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
1420
+ var ToastContext = React13.createContext(null);
1421
+ function useToast() {
1422
+ const ctx = React13.useContext(ToastContext);
1423
+ if (!ctx) {
1424
+ throw new Error("useToast must be used within a ToastProvider or Toaster");
1425
+ }
1426
+ return ctx;
1427
+ }
1428
+ function ToastProvider({ children }) {
1429
+ const [toasts, setToasts] = React13.useState([]);
1430
+ const removeToast = React13.useCallback((id) => {
1431
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1432
+ }, []);
1433
+ const addToast = React13.useCallback(
1434
+ (toast) => {
1435
+ const id = Math.random().toString(36).substring(2, 9);
1436
+ const newToast = { ...toast, id };
1437
+ setToasts((prev) => [...prev, newToast]);
1438
+ const duration = toast.duration ?? 5e3;
1439
+ if (duration > 0) {
1440
+ setTimeout(() => {
1441
+ removeToast(id);
1442
+ }, duration);
1443
+ }
1444
+ return id;
1445
+ },
1446
+ [removeToast]
1447
+ );
1448
+ return /* @__PURE__ */ jsx15(ToastContext.Provider, { value: { toasts, addToast, removeToast }, children });
1449
+ }
1450
+ var variantStyles3 = {
1451
+ info: "border-info-border bg-surface text-fg",
1452
+ success: "border-success-border bg-surface text-fg",
1453
+ warn: "border-warn-border bg-surface text-fg",
1454
+ danger: "border-danger-border bg-surface text-fg"
1455
+ };
1456
+ function Toaster({ className, position = "bottom-end" }) {
1457
+ const ctx = React13.useContext(ToastContext);
1458
+ const toasts = ctx ? ctx.toasts : [];
1459
+ const removeToast = ctx ? ctx.removeToast : () => {
1460
+ };
1461
+ const positionClass = position === "bottom-end" ? "bottom-4 end-4" : position === "bottom-start" ? "bottom-4 start-4" : position === "top-end" ? "top-4 end-4" : "top-4 start-4";
1462
+ return /* @__PURE__ */ jsx15(
1463
+ "div",
1464
+ {
1465
+ "data-slot": "toaster",
1466
+ role: "region",
1467
+ "aria-live": "polite",
1468
+ "aria-label": "Notifications",
1469
+ className: cn("yc-Toaster-root fixed z-50 flex flex-col gap-2 max-w-sm w-full pointer-events-none", positionClass, className),
1470
+ children: toasts.map((toast) => /* @__PURE__ */ jsxs8(
1471
+ "div",
1472
+ {
1473
+ role: "status",
1474
+ "data-slot": "toast",
1475
+ "data-variant": toast.variant || "info",
1476
+ className: cn(
1477
+ "yc-Toaster-toast pointer-events-auto flex w-full items-start justify-between rounded-lg p-3 shadow-2 border transition-all duration-normal",
1478
+ variantStyles3[toast.variant || "info"]
1479
+ ),
1480
+ children: [
1481
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1 pe-2", children: [
1482
+ /* @__PURE__ */ jsx15("h4", { className: "yc-Toaster-title text-sm font-medium", "data-slot": "title", children: toast.title }),
1483
+ toast.description && /* @__PURE__ */ jsx15("p", { className: "yc-Toaster-description mt-0.5 text-xs text-fg-muted", "data-slot": "description", children: toast.description })
1484
+ ] }),
1485
+ /* @__PURE__ */ jsx15(
1486
+ "button",
1487
+ {
1488
+ type: "button",
1489
+ "data-slot": "close",
1490
+ className: "yc-Toaster-close text-fg-muted hover:text-fg text-xs p-1",
1491
+ onClick: () => removeToast(toast.id),
1492
+ "aria-label": "Dismiss",
1493
+ children: "\u2715"
1494
+ }
1495
+ )
1496
+ ]
1497
+ },
1498
+ toast.id
1499
+ ))
1500
+ }
1501
+ );
1502
+ }
1503
+
1504
+ // src/chat/Chat.tsx
1505
+ import * as React21 from "react";
1506
+
1507
+ // src/chat/ChatMarkdown.tsx
1508
+ import * as React16 from "react";
1509
+
1510
+ // src/chat/CodeBlock.tsx
1511
+ import * as React14 from "react";
1512
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
1513
+ function CodeBlock({ code, language = "text", className }) {
1514
+ const [copied, setCopied] = React14.useState(false);
1515
+ const handleCopy = async () => {
1516
+ try {
1517
+ await navigator.clipboard.writeText(code);
1518
+ setCopied(true);
1519
+ setTimeout(() => setCopied(false), 2e3);
1520
+ } catch {
1521
+ }
1522
+ };
1523
+ return /* @__PURE__ */ jsxs9(
1524
+ "div",
1525
+ {
1526
+ "data-slot": "code-block",
1527
+ className: cn(
1528
+ "yc-CodeBlock-root my-2 overflow-hidden rounded-lg border border-border bg-surface-2 text-xs font-mono shadow-1",
1529
+ className
1530
+ ),
1531
+ children: [
1532
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between border-b border-border bg-surface-3 px-3 py-1.5 text-fg-muted", children: [
1533
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold uppercase tracking-wider text-[11px]", children: language }),
1534
+ /* @__PURE__ */ jsx16(
1535
+ "button",
1536
+ {
1537
+ type: "button",
1538
+ onClick: handleCopy,
1539
+ className: "rounded px-2 py-0.5 text-[11px] transition-colors hover:bg-surface hover:text-fg",
1540
+ "aria-label": "Copy code to clipboard",
1541
+ children: copied ? "Copied!" : "Copy"
1542
+ }
1543
+ )
1544
+ ] }),
1545
+ /* @__PURE__ */ jsx16("pre", { className: "overflow-x-auto p-3 text-fg leading-relaxed", children: /* @__PURE__ */ jsx16("code", { children: code }) })
1546
+ ]
1547
+ }
1548
+ );
1549
+ }
1550
+
1551
+ // src/chat/MermaidDiagram.tsx
1552
+ import * as React15 from "react";
1553
+ import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
1554
+ function MermaidDiagram({ chart, className }) {
1555
+ const [showSource, setShowSource] = React15.useState(false);
1556
+ return /* @__PURE__ */ jsxs10(
1557
+ "div",
1558
+ {
1559
+ "data-slot": "mermaid-diagram",
1560
+ className: cn(
1561
+ "yc-MermaidDiagram-root my-3 rounded-lg border border-border bg-surface p-3 text-xs shadow-1",
1562
+ className
1563
+ ),
1564
+ children: [
1565
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between border-b border-border pb-2 mb-2 text-fg-muted font-mono", children: [
1566
+ /* @__PURE__ */ jsx17("span", { className: "font-semibold text-fg", children: "Diagram" }),
1567
+ /* @__PURE__ */ jsx17(
1568
+ "button",
1569
+ {
1570
+ type: "button",
1571
+ onClick: () => setShowSource(!showSource),
1572
+ className: "text-[11px] underline hover:text-fg",
1573
+ children: showSource ? "View rendering" : "View syntax"
1574
+ }
1575
+ )
1576
+ ] }),
1577
+ showSource ? /* @__PURE__ */ jsx17("pre", { className: "overflow-x-auto rounded bg-surface-2 p-3 font-mono text-fg", children: /* @__PURE__ */ jsx17("code", { children: chart }) }) : /* @__PURE__ */ jsx17(
1578
+ "div",
1579
+ {
1580
+ "data-slot": "diagram-viewport",
1581
+ className: "yc-MermaidDiagram-viewport flex items-center justify-center p-4 bg-surface-2 rounded overflow-x-auto",
1582
+ children: /* @__PURE__ */ jsx17("pre", { className: "font-mono text-xs text-fg leading-relaxed", children: chart })
1583
+ }
1584
+ )
1585
+ ]
1586
+ }
1587
+ );
1588
+ }
1589
+
1590
+ // src/chat/ChatMarkdown.tsx
1591
+ import { jsx as jsx18 } from "react/jsx-runtime";
1592
+ function ChatMarkdown({ content, className }) {
1593
+ const blocks = React16.useMemo(() => {
1594
+ const lines = content.split("\n");
1595
+ const result = [];
1596
+ let currentCode = [];
1597
+ let currentLang = "";
1598
+ let inCode = false;
1599
+ let currentText = [];
1600
+ for (let i = 0; i < lines.length; i++) {
1601
+ const line = lines[i];
1602
+ if (line.startsWith("```")) {
1603
+ if (inCode) {
1604
+ const codeString = currentCode.join("\n");
1605
+ if (currentLang === "mermaid") {
1606
+ result.push({ type: "mermaid", content: codeString });
1607
+ } else {
1608
+ result.push({ type: "code", content: codeString, lang: currentLang });
1609
+ }
1610
+ currentCode = [];
1611
+ currentLang = "";
1612
+ inCode = false;
1613
+ } else {
1614
+ if (currentText.length > 0) {
1615
+ result.push({ type: "text", content: currentText.join("\n") });
1616
+ currentText = [];
1617
+ }
1618
+ inCode = true;
1619
+ currentLang = line.replace("```", "").trim();
1620
+ }
1621
+ } else if (inCode) {
1622
+ currentCode.push(line);
1623
+ } else {
1624
+ currentText.push(line);
1625
+ }
1626
+ }
1627
+ if (inCode && currentCode.length > 0) {
1628
+ result.push({ type: "code", content: currentCode.join("\n"), lang: currentLang });
1629
+ } else if (currentText.length > 0) {
1630
+ result.push({ type: "text", content: currentText.join("\n") });
1631
+ }
1632
+ return result;
1633
+ }, [content]);
1634
+ return /* @__PURE__ */ jsx18(
1635
+ "div",
1636
+ {
1637
+ "data-slot": "chat-markdown",
1638
+ className: cn("yc-ChatMarkdown-root text-sm text-fg space-y-2 leading-relaxed", className),
1639
+ children: blocks.map((b, idx) => {
1640
+ if (b.type === "code") {
1641
+ return /* @__PURE__ */ jsx18(CodeBlock, { code: b.content, language: b.lang }, idx);
1642
+ }
1643
+ if (b.type === "mermaid") {
1644
+ return /* @__PURE__ */ jsx18(MermaidDiagram, { chart: b.content }, idx);
1645
+ }
1646
+ return /* @__PURE__ */ jsx18("div", { className: "whitespace-pre-wrap", children: b.content }, idx);
1647
+ })
1648
+ }
1649
+ );
1650
+ }
1651
+
1652
+ // src/chat/MessageToolbar.tsx
1653
+ import * as React17 from "react";
1654
+ import { Fragment, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
1655
+ function MessageToolbar({
1656
+ content,
1657
+ onRetry,
1658
+ onFeedback,
1659
+ className
1660
+ }) {
1661
+ const [copied, setCopied] = React17.useState(false);
1662
+ const [rated, setRated] = React17.useState(null);
1663
+ const handleCopy = async () => {
1664
+ try {
1665
+ await navigator.clipboard.writeText(content);
1666
+ setCopied(true);
1667
+ setTimeout(() => setCopied(false), 2e3);
1668
+ } catch {
1669
+ }
1670
+ };
1671
+ const handleRate = (rating) => {
1672
+ setRated(rating);
1673
+ onFeedback?.(rating);
1674
+ };
1675
+ return /* @__PURE__ */ jsxs11(
1676
+ "div",
1677
+ {
1678
+ "data-slot": "message-toolbar",
1679
+ className: cn(
1680
+ "yc-MessageToolbar-root inline-flex items-center gap-1 rounded-md bg-surface-2 p-0.5 text-xs text-fg-muted border border-border shadow-1",
1681
+ className
1682
+ ),
1683
+ children: [
1684
+ /* @__PURE__ */ jsx19(
1685
+ "button",
1686
+ {
1687
+ type: "button",
1688
+ onClick: handleCopy,
1689
+ className: "rounded px-1.5 py-0.5 hover:bg-surface hover:text-fg",
1690
+ "aria-label": "Copy message text",
1691
+ children: copied ? "Copied" : "Copy"
1692
+ }
1693
+ ),
1694
+ onRetry && /* @__PURE__ */ jsx19(
1695
+ "button",
1696
+ {
1697
+ type: "button",
1698
+ onClick: onRetry,
1699
+ className: "rounded px-1.5 py-0.5 hover:bg-surface hover:text-fg",
1700
+ "aria-label": "Retry message generation",
1701
+ children: "Retry"
1702
+ }
1703
+ ),
1704
+ onFeedback && /* @__PURE__ */ jsxs11(Fragment, { children: [
1705
+ /* @__PURE__ */ jsx19(
1706
+ "button",
1707
+ {
1708
+ type: "button",
1709
+ onClick: () => handleRate("positive"),
1710
+ className: cn(
1711
+ "rounded px-1.5 py-0.5 hover:bg-surface hover:text-fg",
1712
+ rated === "positive" && "text-primary font-bold"
1713
+ ),
1714
+ "aria-label": "Helpful",
1715
+ children: "\u{1F44D}"
1716
+ }
1717
+ ),
1718
+ /* @__PURE__ */ jsx19(
1719
+ "button",
1720
+ {
1721
+ type: "button",
1722
+ onClick: () => handleRate("negative"),
1723
+ className: cn(
1724
+ "rounded px-1.5 py-0.5 hover:bg-surface hover:text-fg",
1725
+ rated === "negative" && "text-danger-fg font-bold"
1726
+ ),
1727
+ "aria-label": "Not helpful",
1728
+ children: "\u{1F44E}"
1729
+ }
1730
+ )
1731
+ ] })
1732
+ ]
1733
+ }
1734
+ );
1735
+ }
1736
+
1737
+ // src/chat/ThinkingIndicator.tsx
1738
+ import * as React18 from "react";
1739
+ import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
1740
+ function ThinkingIndicator({
1741
+ label = "Thinking...",
1742
+ reasoning,
1743
+ className
1744
+ }) {
1745
+ const [open, setOpen] = React18.useState(false);
1746
+ return /* @__PURE__ */ jsxs12(
1747
+ "div",
1748
+ {
1749
+ "data-slot": "thinking-indicator",
1750
+ className: cn(
1751
+ "yc-ThinkingIndicator-root inline-flex flex-col gap-1 text-xs text-fg-muted",
1752
+ className
1753
+ ),
1754
+ children: [
1755
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
1756
+ /* @__PURE__ */ jsxs12("span", { className: "flex gap-1 items-center", children: [
1757
+ /* @__PURE__ */ jsx20("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-fg-muted" }),
1758
+ /* @__PURE__ */ jsx20("span", { className: "h-1.5 w-1.5 animate-bounce [animation-delay:0.2s] rounded-full bg-fg-muted" }),
1759
+ /* @__PURE__ */ jsx20("span", { className: "h-1.5 w-1.5 animate-bounce [animation-delay:0.4s] rounded-full bg-fg-muted" })
1760
+ ] }),
1761
+ /* @__PURE__ */ jsx20("span", { className: "font-medium", children: label }),
1762
+ reasoning && /* @__PURE__ */ jsx20(
1763
+ "button",
1764
+ {
1765
+ type: "button",
1766
+ onClick: () => setOpen(!open),
1767
+ className: "text-[11px] underline hover:text-fg",
1768
+ children: open ? "Hide details" : "Show details"
1769
+ }
1770
+ )
1771
+ ] }),
1772
+ open && reasoning && /* @__PURE__ */ jsx20("div", { className: "mt-1 rounded border border-border bg-surface-2 p-2 font-mono text-[11px] text-fg whitespace-pre-wrap", children: reasoning })
1773
+ ]
1774
+ }
1775
+ );
1776
+ }
1777
+
1778
+ // src/chat/ApprovalCard.tsx
1779
+ import * as React19 from "react";
1780
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1781
+ var levelBadgeVariant = {
1782
+ info: "info",
1783
+ warn: "warn",
1784
+ danger: "danger"
1785
+ };
1786
+ var levelBorderStyles = {
1787
+ info: "border-info-border bg-info-bg/30",
1788
+ warn: "border-warn-border bg-warn-bg/30",
1789
+ danger: "border-danger-border bg-danger-bg/30"
1790
+ };
1791
+ function ApprovalCard({
1792
+ id,
1793
+ level,
1794
+ label,
1795
+ details,
1796
+ onDecide,
1797
+ status = "pending",
1798
+ className
1799
+ }) {
1800
+ const [loading, setLoading] = React19.useState(false);
1801
+ const [currentStatus, setCurrentStatus] = React19.useState(status);
1802
+ const handleDecision = async (decision) => {
1803
+ try {
1804
+ setLoading(true);
1805
+ if (onDecide) {
1806
+ await onDecide(id, decision);
1807
+ } else {
1808
+ await fetch(`/api/v1/approvals/${encodeURIComponent(id)}/decide`, {
1809
+ method: "POST",
1810
+ headers: { "Content-Type": "application/json" },
1811
+ body: JSON.stringify({ decision })
1812
+ });
1813
+ }
1814
+ setCurrentStatus(decision);
1815
+ } catch (err) {
1816
+ console.error("Failed to submit approval decision:", err);
1817
+ } finally {
1818
+ setLoading(false);
1819
+ }
1820
+ };
1821
+ return /* @__PURE__ */ jsxs13(
1822
+ "div",
1823
+ {
1824
+ "data-slot": "approval-card",
1825
+ "data-risk-level": level,
1826
+ className: cn(
1827
+ "yc-ApprovalCard-root rounded-lg border p-4 shadow-1 transition-colors duration-fast",
1828
+ levelBorderStyles[level],
1829
+ className
1830
+ ),
1831
+ children: [
1832
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between gap-2 pb-2", children: [
1833
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
1834
+ /* @__PURE__ */ jsx21(Badge, { variant: levelBadgeVariant[level], children: level.toUpperCase() }),
1835
+ /* @__PURE__ */ jsx21("span", { className: "yc-ApprovalCard-title text-sm font-semibold text-fg", "data-slot": "title", children: label })
1836
+ ] }),
1837
+ currentStatus !== "pending" && /* @__PURE__ */ jsx21(Badge, { variant: currentStatus === "approved" ? "success" : "danger", children: currentStatus === "approved" ? "Approved" : "Rejected" })
1838
+ ] }),
1839
+ details && Object.keys(details).length > 0 && /* @__PURE__ */ jsx21("div", { className: "yc-ApprovalCard-details mt-2 rounded bg-surface/80 p-2.5 text-xs text-fg-muted font-mono", "data-slot": "details", children: /* @__PURE__ */ jsx21("pre", { className: "overflow-x-auto whitespace-pre-wrap", children: JSON.stringify(details, null, 2) }) }),
1840
+ currentStatus === "pending" && /* @__PURE__ */ jsxs13("div", { className: "yc-ApprovalCard-actions mt-3 flex items-center justify-end gap-2", "data-slot": "actions", children: [
1841
+ /* @__PURE__ */ jsx21(
1842
+ Button,
1843
+ {
1844
+ size: "sm",
1845
+ variant: "ghost",
1846
+ disabled: loading,
1847
+ onClick: () => handleDecision("rejected"),
1848
+ children: "Reject"
1849
+ }
1850
+ ),
1851
+ /* @__PURE__ */ jsx21(
1852
+ Button,
1853
+ {
1854
+ size: "sm",
1855
+ variant: level === "danger" ? "danger" : "primary",
1856
+ loading,
1857
+ onClick: () => handleDecision("approved"),
1858
+ children: "Approve & Continue"
1859
+ }
1860
+ )
1861
+ ] })
1862
+ ]
1863
+ }
1864
+ );
1865
+ }
1866
+
1867
+ // src/chat/ToolTraceCard.tsx
1868
+ import * as React20 from "react";
1869
+ import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1870
+ function ToolTraceCard({
1871
+ trace,
1872
+ className,
1873
+ defaultExpanded = false
1874
+ }) {
1875
+ const [expanded, setExpanded] = React20.useState(defaultExpanded);
1876
+ const statusVariant = {
1877
+ running: "info",
1878
+ success: "success",
1879
+ error: "danger"
1880
+ };
1881
+ return /* @__PURE__ */ jsxs14(
1882
+ "div",
1883
+ {
1884
+ "data-slot": "tool-trace-card",
1885
+ className: cn(
1886
+ "yc-ToolTraceCard-root my-1.5 rounded-lg border border-border bg-surface text-fg shadow-1 text-xs",
1887
+ className
1888
+ ),
1889
+ children: [
1890
+ /* @__PURE__ */ jsxs14(
1891
+ "button",
1892
+ {
1893
+ type: "button",
1894
+ onClick: () => setExpanded(!expanded),
1895
+ "data-slot": "header",
1896
+ className: "yc-ToolTraceCard-header flex w-full items-center justify-between p-2.5 text-start font-mono transition-colors hover:bg-surface-2",
1897
+ children: [
1898
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
1899
+ /* @__PURE__ */ jsx22("span", { className: "font-semibold text-fg", children: trace.toolName }),
1900
+ /* @__PURE__ */ jsx22(Badge, { variant: statusVariant[trace.status], children: trace.status }),
1901
+ trace.durationMs !== void 0 && /* @__PURE__ */ jsxs14("span", { className: "text-fg-muted", children: [
1902
+ "(",
1903
+ trace.durationMs,
1904
+ "ms)"
1905
+ ] })
1906
+ ] }),
1907
+ /* @__PURE__ */ jsx22("span", { className: "text-fg-muted", children: expanded ? "\u25B2" : "\u25BC" })
1908
+ ]
1909
+ }
1910
+ ),
1911
+ expanded && /* @__PURE__ */ jsxs14("div", { "data-slot": "details", className: "yc-ToolTraceCard-details border-t border-border p-2.5 font-mono space-y-2", children: [
1912
+ trace.input !== void 0 && /* @__PURE__ */ jsxs14("div", { children: [
1913
+ /* @__PURE__ */ jsx22("div", { className: "text-fg-muted text-[10px] uppercase font-semibold", children: "Input" }),
1914
+ /* @__PURE__ */ jsx22("pre", { className: "mt-1 max-h-40 overflow-auto rounded bg-surface-2 p-2 text-fg", children: typeof trace.input === "string" ? trace.input : JSON.stringify(trace.input, null, 2) })
1915
+ ] }),
1916
+ trace.output !== void 0 && /* @__PURE__ */ jsxs14("div", { children: [
1917
+ /* @__PURE__ */ jsx22("div", { className: "text-fg-muted text-[10px] uppercase font-semibold", children: "Output" }),
1918
+ /* @__PURE__ */ jsx22("pre", { className: "mt-1 max-h-40 overflow-auto rounded bg-surface-2 p-2 text-fg", children: typeof trace.output === "string" ? trace.output : JSON.stringify(trace.output, null, 2) })
1919
+ ] })
1920
+ ] })
1921
+ ]
1922
+ }
1923
+ );
1924
+ }
1925
+
1926
+ // src/chat/ExecutionPlanCard.tsx
1927
+ import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1928
+ function ExecutionPlanCard({
1929
+ steps,
1930
+ className,
1931
+ title = "Execution Plan"
1932
+ }) {
1933
+ if (!steps || steps.length === 0) return null;
1934
+ return /* @__PURE__ */ jsxs15(
1935
+ "div",
1936
+ {
1937
+ "data-slot": "execution-plan-card",
1938
+ className: cn(
1939
+ "yc-ExecutionPlanCard-root my-2 rounded-lg border border-border bg-surface p-3 text-xs shadow-1",
1940
+ className
1941
+ ),
1942
+ children: [
1943
+ /* @__PURE__ */ jsxs15("div", { className: "font-semibold text-fg pb-2 flex items-center justify-between", children: [
1944
+ /* @__PURE__ */ jsx23("span", { children: title }),
1945
+ /* @__PURE__ */ jsxs15("span", { className: "text-fg-muted", children: [
1946
+ steps.filter((s) => s.status === "completed").length,
1947
+ "/",
1948
+ steps.length
1949
+ ] })
1950
+ ] }),
1951
+ /* @__PURE__ */ jsx23("div", { className: "space-y-1.5", children: steps.map((step, idx) => {
1952
+ const isDone = step.status === "completed";
1953
+ const isRunning = step.status === "running";
1954
+ const isFailed = step.status === "failed";
1955
+ return /* @__PURE__ */ jsxs15(
1956
+ "div",
1957
+ {
1958
+ "data-slot": "step",
1959
+ "data-status": step.status,
1960
+ className: "yc-ExecutionPlanCard-step flex items-start gap-2",
1961
+ children: [
1962
+ /* @__PURE__ */ jsx23(
1963
+ "span",
1964
+ {
1965
+ className: cn(
1966
+ "mt-0.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-bold",
1967
+ isDone ? "bg-success-fg text-white" : isRunning ? "animate-spin border-2 border-primary border-t-transparent" : isFailed ? "bg-danger-fg text-white" : "bg-surface-3 text-fg-muted"
1968
+ ),
1969
+ children: isDone ? "\u2713" : isFailed ? "\u2715" : isRunning ? "" : idx + 1
1970
+ }
1971
+ ),
1972
+ /* @__PURE__ */ jsx23(
1973
+ "span",
1974
+ {
1975
+ className: cn(
1976
+ "flex-1 text-fg",
1977
+ isDone && "line-through text-fg-muted",
1978
+ isRunning && "font-medium text-primary"
1979
+ ),
1980
+ children: step.description
1981
+ }
1982
+ )
1983
+ ]
1984
+ },
1985
+ step.id || idx
1986
+ );
1987
+ }) })
1988
+ ]
1989
+ }
1990
+ );
1991
+ }
1992
+
1993
+ // src/chat/Chat.tsx
1994
+ import { Fragment as Fragment2, jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
1995
+ var ChatContext = React21.createContext(null);
1996
+ function useChatContext() {
1997
+ const ctx = React21.useContext(ChatContext);
1998
+ if (!ctx) throw new Error("Chat compound components must be rendered inside <Chat.Root>");
1999
+ return ctx;
2000
+ }
2001
+ function ChatRoot({
2002
+ messages,
2003
+ onSendMessage,
2004
+ loading = false,
2005
+ slotHooks,
2006
+ children,
2007
+ className
2008
+ }) {
2009
+ const [activeAttachments, setActiveAttachments] = React21.useState([]);
2010
+ return /* @__PURE__ */ jsx24(
2011
+ ChatContext.Provider,
2012
+ {
2013
+ value: {
2014
+ messages,
2015
+ onSendMessage,
2016
+ loading,
2017
+ activeAttachments,
2018
+ setActiveAttachments,
2019
+ slotHooks
2020
+ },
2021
+ children: /* @__PURE__ */ jsx24(
2022
+ "div",
2023
+ {
2024
+ "data-slot": "chat-root",
2025
+ className: cn("yc-Chat-root flex flex-col h-full w-full bg-surface text-fg", className),
2026
+ children
2027
+ }
2028
+ )
2029
+ }
2030
+ );
2031
+ }
2032
+ function ChatThread({
2033
+ className,
2034
+ emptyTitle = "How can I assist you today?",
2035
+ emptyDescription = "Start a conversation by typing a message below."
2036
+ }) {
2037
+ const { messages } = useChatContext();
2038
+ const threadEndRef = React21.useRef(null);
2039
+ React21.useEffect(() => {
2040
+ threadEndRef.current?.scrollIntoView({ behavior: "smooth" });
2041
+ }, [messages]);
2042
+ return /* @__PURE__ */ jsxs16(
2043
+ "div",
2044
+ {
2045
+ "data-slot": "chat-thread",
2046
+ className: cn("yc-Chat-thread flex-1 overflow-y-auto p-4 space-y-4", className),
2047
+ children: [
2048
+ messages.length === 0 ? /* @__PURE__ */ jsx24(EmptyState, { title: emptyTitle, description: emptyDescription, className: "h-full" }) : messages.map((msg) => /* @__PURE__ */ jsx24(ChatMessageItem, { message: msg }, msg.id)),
2049
+ /* @__PURE__ */ jsx24("div", { ref: threadEndRef })
2050
+ ]
2051
+ }
2052
+ );
2053
+ }
2054
+ function ChatMessageItem({ message, className }) {
2055
+ const { slotHooks } = useChatContext();
2056
+ const isUser = message.role === "user";
2057
+ const isSystem = message.role === "system";
2058
+ if (slotHooks?.messageRenderer) {
2059
+ const custom = slotHooks.messageRenderer(message);
2060
+ if (custom) return /* @__PURE__ */ jsx24(Fragment2, { children: custom });
2061
+ }
2062
+ return /* @__PURE__ */ jsxs16(
2063
+ "div",
2064
+ {
2065
+ "data-slot": "chat-message",
2066
+ "data-role": message.role,
2067
+ className: cn(
2068
+ "yc-Chat-message group flex w-full gap-3",
2069
+ isUser ? "justify-end" : "justify-start",
2070
+ className
2071
+ ),
2072
+ children: [
2073
+ !isUser && /* @__PURE__ */ jsx24(Avatar, { size: "sm", className: "mt-1", children: message.avatarUrl ? /* @__PURE__ */ jsx24(AvatarImage, { src: message.avatarUrl, alt: message.authorName || "Assistant" }) : /* @__PURE__ */ jsx24(AvatarFallback, { children: (message.authorName || "AI").substring(0, 2).toUpperCase() }) }),
2074
+ /* @__PURE__ */ jsxs16(
2075
+ "div",
2076
+ {
2077
+ className: cn(
2078
+ "flex flex-col max-w-[80%] gap-1.5",
2079
+ isUser ? "items-end" : "items-start"
2080
+ ),
2081
+ children: [
2082
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 text-xs text-fg-muted", children: [
2083
+ /* @__PURE__ */ jsx24("span", { className: "font-semibold", children: message.authorName || (isUser ? "You" : "Assistant") }),
2084
+ /* @__PURE__ */ jsx24("span", { children: message.createdAt })
2085
+ ] }),
2086
+ /* @__PURE__ */ jsxs16(
2087
+ "div",
2088
+ {
2089
+ "data-slot": "message-bubble",
2090
+ className: cn(
2091
+ "yc-Chat-bubble rounded-2xl px-4 py-2.5 shadow-1 text-sm leading-relaxed",
2092
+ isUser ? "bg-primary text-primary-fg rounded-be-sm" : isSystem ? "bg-surface-2 text-fg-muted border border-border" : "bg-surface-2 text-fg rounded-bs-sm border border-border"
2093
+ ),
2094
+ children: [
2095
+ message.reasoning && /* @__PURE__ */ jsx24("div", { className: "mb-2", children: /* @__PURE__ */ jsx24(ThinkingIndicator, { reasoning: message.reasoning }) }),
2096
+ isUser ? /* @__PURE__ */ jsx24("div", { className: "whitespace-pre-wrap", children: message.content }) : /* @__PURE__ */ jsx24(ChatMarkdown, { content: message.content }),
2097
+ message.executionPlan && message.executionPlan.length > 0 && /* @__PURE__ */ jsx24(ExecutionPlanCard, { steps: message.executionPlan }),
2098
+ message.toolTraces && message.toolTraces.length > 0 && /* @__PURE__ */ jsx24("div", { className: "mt-2 space-y-1", children: message.toolTraces.map((trace) => /* @__PURE__ */ jsx24(ToolTraceCard, { trace }, trace.id)) }),
2099
+ message.approval && /* @__PURE__ */ jsx24("div", { className: "mt-2", children: /* @__PURE__ */ jsx24(
2100
+ ApprovalCard,
2101
+ {
2102
+ id: message.approval.id,
2103
+ level: message.approval.level,
2104
+ label: message.approval.label,
2105
+ details: message.approval.details,
2106
+ status: message.approval.status
2107
+ }
2108
+ ) })
2109
+ ]
2110
+ }
2111
+ ),
2112
+ !isUser && /* @__PURE__ */ jsx24("div", { className: "opacity-0 group-hover:opacity-100 transition-opacity duration-fast", children: /* @__PURE__ */ jsx24(MessageToolbar, { content: message.content }) })
2113
+ ]
2114
+ }
2115
+ ),
2116
+ isUser && /* @__PURE__ */ jsx24(Avatar, { size: "sm", className: "mt-1", children: message.avatarUrl ? /* @__PURE__ */ jsx24(AvatarImage, { src: message.avatarUrl, alt: "User" }) : /* @__PURE__ */ jsx24(AvatarFallback, { children: "ME" }) })
2117
+ ]
2118
+ }
2119
+ );
2120
+ }
2121
+ function ChatAttachments({ className }) {
2122
+ const { activeAttachments, setActiveAttachments } = useChatContext();
2123
+ if (activeAttachments.length === 0) return null;
2124
+ return /* @__PURE__ */ jsx24(
2125
+ "div",
2126
+ {
2127
+ "data-slot": "chat-attachments",
2128
+ className: cn("yc-Chat-attachments flex flex-wrap gap-2 px-4 py-2 bg-surface-2 border-t border-border", className),
2129
+ children: activeAttachments.map((att) => /* @__PURE__ */ jsxs16(
2130
+ "div",
2131
+ {
2132
+ "data-slot": "attachment-item",
2133
+ className: "yc-Chat-attachment flex items-center gap-1.5 rounded-md bg-surface px-2.5 py-1 text-xs border border-border shadow-1",
2134
+ children: [
2135
+ /* @__PURE__ */ jsx24("span", { className: "truncate max-w-[150px]", children: att.name }),
2136
+ /* @__PURE__ */ jsx24(
2137
+ "button",
2138
+ {
2139
+ type: "button",
2140
+ className: "text-fg-muted hover:text-danger-fg",
2141
+ onClick: () => setActiveAttachments((prev) => prev.filter((a) => a.id !== att.id)),
2142
+ "aria-label": `Remove ${att.name}`,
2143
+ children: "\u2715"
2144
+ }
2145
+ )
2146
+ ]
2147
+ },
2148
+ att.id
2149
+ ))
2150
+ }
2151
+ );
2152
+ }
2153
+ function ChatComposer({
2154
+ placeholder = "Type a message...",
2155
+ className
2156
+ }) {
2157
+ const { onSendMessage, loading, activeAttachments, setActiveAttachments, slotHooks } = useChatContext();
2158
+ const [text, setText] = React21.useState("");
2159
+ const fileInputRef = React21.useRef(null);
2160
+ const handleSubmit = async (e) => {
2161
+ e?.preventDefault();
2162
+ const trimmed = text.trim();
2163
+ if (!trimmed && activeAttachments.length === 0) return;
2164
+ if (loading) return;
2165
+ if (slotHooks?.beforeSend) {
2166
+ const result = await slotHooks.beforeSend(trimmed, activeAttachments);
2167
+ if (result === false) return;
2168
+ if (typeof result === "string") {
2169
+ await onSendMessage(result, activeAttachments);
2170
+ setText("");
2171
+ setActiveAttachments([]);
2172
+ return;
2173
+ }
2174
+ }
2175
+ await onSendMessage(trimmed, activeAttachments);
2176
+ setText("");
2177
+ setActiveAttachments([]);
2178
+ };
2179
+ const handleKeyDown = (e) => {
2180
+ if (e.key === "Enter" && !e.shiftKey) {
2181
+ e.preventDefault();
2182
+ handleSubmit();
2183
+ }
2184
+ };
2185
+ const handleFileChange = (e) => {
2186
+ const files = e.target.files;
2187
+ if (!files) return;
2188
+ const newAttachments = Array.from(files).map((f) => ({
2189
+ id: Math.random().toString(36).substring(2, 9),
2190
+ name: f.name,
2191
+ mimeType: f.type,
2192
+ sizeBytes: f.size
2193
+ }));
2194
+ setActiveAttachments((prev) => [...prev, ...newAttachments]);
2195
+ };
2196
+ return /* @__PURE__ */ jsxs16(
2197
+ "form",
2198
+ {
2199
+ "data-slot": "chat-composer",
2200
+ onSubmit: handleSubmit,
2201
+ className: cn(
2202
+ "yc-Chat-composer flex flex-col gap-2 p-3 border-t border-border bg-surface",
2203
+ className
2204
+ ),
2205
+ children: [
2206
+ /* @__PURE__ */ jsx24(ChatAttachments, {}),
2207
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-end gap-2", children: [
2208
+ /* @__PURE__ */ jsx24(
2209
+ "input",
2210
+ {
2211
+ ref: fileInputRef,
2212
+ type: "file",
2213
+ multiple: true,
2214
+ className: "hidden",
2215
+ onChange: handleFileChange
2216
+ }
2217
+ ),
2218
+ /* @__PURE__ */ jsx24(
2219
+ Button,
2220
+ {
2221
+ type: "button",
2222
+ variant: "ghost",
2223
+ size: "sm",
2224
+ onClick: () => fileInputRef.current?.click(),
2225
+ "aria-label": "Attach file",
2226
+ className: "h-10 px-2.5 text-fg-muted",
2227
+ children: "\u{1F4CE}"
2228
+ }
2229
+ ),
2230
+ slotHooks?.composerAction,
2231
+ /* @__PURE__ */ jsx24(
2232
+ "textarea",
2233
+ {
2234
+ value: text,
2235
+ onChange: (e) => setText(e.target.value),
2236
+ onKeyDown: handleKeyDown,
2237
+ placeholder,
2238
+ rows: 1,
2239
+ className: "flex-1 max-h-32 min-h-[44px] resize-none rounded-lg border border-border bg-surface-2 p-2.5 text-sm text-fg placeholder:text-fg-muted focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary",
2240
+ "data-slot": "input"
2241
+ }
2242
+ ),
2243
+ /* @__PURE__ */ jsx24(
2244
+ Button,
2245
+ {
2246
+ type: "submit",
2247
+ variant: "primary",
2248
+ size: "sm",
2249
+ disabled: loading || !text.trim() && activeAttachments.length === 0,
2250
+ loading,
2251
+ className: "h-10 px-4",
2252
+ children: "Send"
2253
+ }
2254
+ )
2255
+ ] })
2256
+ ]
2257
+ }
2258
+ );
2259
+ }
2260
+ var Chat = {
2261
+ Root: ChatRoot,
2262
+ Thread: ChatThread,
2263
+ Message: ChatMessageItem,
2264
+ Composer: ChatComposer,
2265
+ Attachments: ChatAttachments
2266
+ };
2267
+
2268
+ // src/chat/ChatConnected.tsx
2269
+ import * as React22 from "react";
2270
+ import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
2271
+ function ChatConnected({
2272
+ threadId,
2273
+ initialMessages = [],
2274
+ slotHooks,
2275
+ className,
2276
+ onMessageSent
2277
+ }) {
2278
+ const [messages, setMessages] = React22.useState(initialMessages);
2279
+ const [loading, setLoading] = React22.useState(false);
2280
+ const handleSendMessage = async (content, attachments) => {
2281
+ const userMessage = {
2282
+ id: Math.random().toString(36).substring(2, 9),
2283
+ role: "user",
2284
+ content,
2285
+ createdAt: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
2286
+ attachments
2287
+ };
2288
+ setMessages((prev) => [...prev, userMessage]);
2289
+ onMessageSent?.(userMessage);
2290
+ setLoading(true);
2291
+ try {
2292
+ const res = await fetch(`/api/v1/threads/${encodeURIComponent(threadId)}/messages`, {
2293
+ method: "POST",
2294
+ headers: { "Content-Type": "application/json" },
2295
+ body: JSON.stringify({ content, attachments })
2296
+ });
2297
+ if (!res.ok) {
2298
+ throw new Error(`Server returned status ${res.status}`);
2299
+ }
2300
+ const data = await res.json();
2301
+ const assistantMessage = {
2302
+ id: data.id || Math.random().toString(36).substring(2, 9),
2303
+ role: "assistant",
2304
+ content: data.content || data.reply || "",
2305
+ createdAt: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
2306
+ toolTraces: data.toolTraces,
2307
+ executionPlan: data.executionPlan,
2308
+ approval: data.approval
2309
+ };
2310
+ setMessages((prev) => [...prev, assistantMessage]);
2311
+ } catch (err) {
2312
+ console.error("Failed to send message:", err);
2313
+ const errorMessage = {
2314
+ id: Math.random().toString(36).substring(2, 9),
2315
+ role: "system",
2316
+ content: "Unable to connect to the assistant. Please try again.",
2317
+ createdAt: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
2318
+ status: "error"
2319
+ };
2320
+ setMessages((prev) => [...prev, errorMessage]);
2321
+ } finally {
2322
+ setLoading(false);
2323
+ }
2324
+ };
2325
+ return /* @__PURE__ */ jsxs17(
2326
+ ChatRoot,
2327
+ {
2328
+ messages,
2329
+ onSendMessage: handleSendMessage,
2330
+ loading,
2331
+ slotHooks,
2332
+ className,
2333
+ children: [
2334
+ /* @__PURE__ */ jsx25(ChatThread, {}),
2335
+ /* @__PURE__ */ jsx25(ChatComposer, {})
2336
+ ]
2337
+ }
2338
+ );
2339
+ }
2340
+
2341
+ // src/chat/ActivityLogDrawer.tsx
2342
+ import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
2343
+ function ActivityLogDrawer({
2344
+ traces,
2345
+ open,
2346
+ onOpenChange,
2347
+ trigger
2348
+ }) {
2349
+ return /* @__PURE__ */ jsxs18(Sheet, { open, onOpenChange, children: [
2350
+ trigger && /* @__PURE__ */ jsx26(SheetTrigger, { asChild: true, children: trigger }),
2351
+ /* @__PURE__ */ jsxs18(SheetContent, { side: "end", className: "yc-ActivityLogDrawer-content flex flex-col gap-4", children: [
2352
+ /* @__PURE__ */ jsxs18(SheetHeader, { children: [
2353
+ /* @__PURE__ */ jsx26(SheetTitle, { children: "Activity Log" }),
2354
+ /* @__PURE__ */ jsx26(SheetDescription, { children: "Audit log of agent execution traces and tool calls." })
2355
+ ] }),
2356
+ /* @__PURE__ */ jsx26(
2357
+ "div",
2358
+ {
2359
+ "data-slot": "activity-log-drawer",
2360
+ className: "yc-ActivityLogDrawer-root flex-1 overflow-y-auto space-y-2 pe-1",
2361
+ children: traces.length === 0 ? /* @__PURE__ */ jsx26("div", { className: "text-center text-xs text-fg-muted py-8", children: "No activity recorded for this session." }) : traces.map((trace) => /* @__PURE__ */ jsx26(ToolTraceCard, { trace, defaultExpanded: false }, trace.id))
2362
+ }
2363
+ )
2364
+ ] })
2365
+ ] });
2366
+ }
2367
+
2368
+ // src/chat/ModelSelector.tsx
2369
+ import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
2370
+ function ModelSelector({
2371
+ models,
2372
+ selectedModelId,
2373
+ onSelectModel,
2374
+ className
2375
+ }) {
2376
+ const currentModel = models.find((m) => m.id === selectedModelId) || models[0];
2377
+ return /* @__PURE__ */ jsx27(
2378
+ "div",
2379
+ {
2380
+ "data-slot": "model-selector",
2381
+ className: cn("yc-ModelSelector-root inline-block", className),
2382
+ children: /* @__PURE__ */ jsxs19(Menu, { children: [
2383
+ /* @__PURE__ */ jsxs19(MenuTrigger, { className: "rounded-md border border-border bg-surface px-2.5 py-1 text-xs font-medium text-fg shadow-1 hover:bg-surface-2", children: [
2384
+ /* @__PURE__ */ jsx27("span", { className: "me-1 text-fg-muted font-normal", children: "Model:" }),
2385
+ /* @__PURE__ */ jsx27("span", { children: currentModel ? currentModel.name : "Select model" }),
2386
+ /* @__PURE__ */ jsx27("span", { className: "ms-1.5 text-fg-muted", children: "\u25BE" })
2387
+ ] }),
2388
+ /* @__PURE__ */ jsx27(MenuContent, { align: "start", children: models.map((m) => /* @__PURE__ */ jsx27(
2389
+ MenuItem,
2390
+ {
2391
+ onClick: () => onSelectModel?.(m.id),
2392
+ className: cn(m.id === currentModel?.id && "font-semibold text-primary"),
2393
+ children: /* @__PURE__ */ jsxs19("div", { className: "flex flex-col text-start", children: [
2394
+ /* @__PURE__ */ jsx27("span", { children: m.name }),
2395
+ m.provider && /* @__PURE__ */ jsx27("span", { className: "text-[10px] text-fg-muted font-normal", children: m.provider })
2396
+ ] })
2397
+ },
2398
+ m.id
2399
+ )) })
2400
+ ] })
2401
+ }
2402
+ );
2403
+ }
2404
+
2405
+ // src/notes/RecordSearch.tsx
2406
+ import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
2407
+ function RecordSearch({
2408
+ searchQuery,
2409
+ onSearchChange,
2410
+ selectedFilter,
2411
+ onFilterChange,
2412
+ filterOptions = [
2413
+ { id: "all", label: "All Records" },
2414
+ { id: "pinned", label: "Pinned" },
2415
+ { id: "recent", label: "Recent" }
2416
+ ],
2417
+ placeholder = "Search records...",
2418
+ className
2419
+ }) {
2420
+ return /* @__PURE__ */ jsxs20(
2421
+ "div",
2422
+ {
2423
+ "data-slot": "record-search",
2424
+ className: cn("yc-RecordSearch-root flex flex-col gap-2.5", className),
2425
+ children: [
2426
+ /* @__PURE__ */ jsxs20("div", { className: "relative flex items-center", children: [
2427
+ /* @__PURE__ */ jsx28("span", { className: "absolute start-3 text-fg-muted text-sm", children: "\u{1F50D}" }),
2428
+ /* @__PURE__ */ jsx28(
2429
+ "input",
2430
+ {
2431
+ type: "text",
2432
+ value: searchQuery,
2433
+ onChange: (e) => onSearchChange(e.target.value),
2434
+ placeholder,
2435
+ className: "w-full rounded-lg border border-border bg-surface-2 py-2 ps-9 pe-3 text-sm text-fg placeholder:text-fg-muted focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary",
2436
+ "data-slot": "search-input"
2437
+ }
2438
+ ),
2439
+ searchQuery && /* @__PURE__ */ jsx28(
2440
+ "button",
2441
+ {
2442
+ type: "button",
2443
+ onClick: () => onSearchChange(""),
2444
+ className: "absolute end-3 text-fg-muted hover:text-fg text-xs",
2445
+ "aria-label": "Clear search",
2446
+ children: "\u2715"
2447
+ }
2448
+ )
2449
+ ] }),
2450
+ /* @__PURE__ */ jsx28(
2451
+ "div",
2452
+ {
2453
+ "data-slot": "filter-chips",
2454
+ className: "yc-RecordSearch-chips flex flex-wrap gap-1.5",
2455
+ children: filterOptions.map((opt) => {
2456
+ const isSelected = opt.id === selectedFilter;
2457
+ return /* @__PURE__ */ jsxs20(
2458
+ Chip,
2459
+ {
2460
+ selected: isSelected,
2461
+ onClick: () => onFilterChange(opt.id),
2462
+ children: [
2463
+ opt.label,
2464
+ opt.count !== void 0 && /* @__PURE__ */ jsxs20("span", { className: "ms-1.5 text-xs text-fg-muted font-normal", children: [
2465
+ "(",
2466
+ opt.count,
2467
+ ")"
2468
+ ] })
2469
+ ]
2470
+ },
2471
+ opt.id
2472
+ );
2473
+ })
2474
+ }
2475
+ )
2476
+ ]
2477
+ }
2478
+ );
2479
+ }
2480
+
2481
+ // src/notes/NotesList.tsx
2482
+ import { jsx as jsx29, jsxs as jsxs21 } from "react/jsx-runtime";
2483
+ function NotesList({
2484
+ notes,
2485
+ selectedNoteId,
2486
+ onSelectNote,
2487
+ className,
2488
+ emptyTitle = "No notes found",
2489
+ emptyDescription = "Create a new note or adjust your search filter."
2490
+ }) {
2491
+ if (notes.length === 0) {
2492
+ return /* @__PURE__ */ jsx29(EmptyState, { title: emptyTitle, description: emptyDescription, className });
2493
+ }
2494
+ return /* @__PURE__ */ jsx29(
2495
+ "div",
2496
+ {
2497
+ "data-slot": "notes-list",
2498
+ className: cn("yc-NotesList-root flex flex-col gap-2 overflow-y-auto", className),
2499
+ children: notes.map((note) => {
2500
+ const isSelected = note.id === selectedNoteId;
2501
+ return /* @__PURE__ */ jsxs21(
2502
+ "button",
2503
+ {
2504
+ type: "button",
2505
+ onClick: () => onSelectNote(note),
2506
+ "data-slot": "note-item",
2507
+ "data-selected": isSelected ? "true" : void 0,
2508
+ className: cn(
2509
+ "yc-NotesList-item flex flex-col text-start rounded-lg border p-3 transition-colors duration-fast shadow-1",
2510
+ isSelected ? "border-primary bg-primary-subtle/20" : "border-border bg-surface hover:bg-surface-2"
2511
+ ),
2512
+ children: [
2513
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-center justify-between gap-2 pb-1", children: [
2514
+ /* @__PURE__ */ jsxs21("span", { className: "font-semibold text-sm text-fg truncate", children: [
2515
+ note.pinned && /* @__PURE__ */ jsx29("span", { className: "me-1 text-primary", children: "\u{1F4CC}" }),
2516
+ note.title || "Untitled Note"
2517
+ ] }),
2518
+ /* @__PURE__ */ jsx29("span", { className: "text-[11px] text-fg-muted shrink-0", children: note.updatedAt })
2519
+ ] }),
2520
+ /* @__PURE__ */ jsx29("p", { className: "text-xs text-fg-muted line-clamp-2 leading-relaxed", children: note.content || "No content" }),
2521
+ note.tags && note.tags.length > 0 && /* @__PURE__ */ jsx29("div", { className: "mt-2 flex flex-wrap gap-1", children: note.tags.map((tag) => /* @__PURE__ */ jsx29(Badge, { variant: "neutral", children: tag }, tag)) })
2522
+ ]
2523
+ },
2524
+ note.id
2525
+ );
2526
+ })
2527
+ }
2528
+ );
2529
+ }
2530
+
2531
+ // src/notes/NoteView.tsx
2532
+ import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
2533
+ function NoteView({
2534
+ note,
2535
+ onEdit,
2536
+ onDelete,
2537
+ onTogglePin,
2538
+ className
2539
+ }) {
2540
+ return /* @__PURE__ */ jsxs22(
2541
+ "div",
2542
+ {
2543
+ "data-slot": "note-view",
2544
+ className: cn(
2545
+ "yc-NoteView-root flex flex-col h-full rounded-lg border border-border bg-surface p-6 shadow-1",
2546
+ className
2547
+ ),
2548
+ children: [
2549
+ /* @__PURE__ */ jsxs22("div", { className: "flex items-start justify-between gap-4 border-b border-border pb-4", children: [
2550
+ /* @__PURE__ */ jsxs22("div", { children: [
2551
+ /* @__PURE__ */ jsxs22("h2", { className: "yc-NoteView-title text-xl font-bold text-fg flex items-center gap-2", children: [
2552
+ note.pinned && /* @__PURE__ */ jsx30("span", { className: "text-primary text-base", children: "\u{1F4CC}" }),
2553
+ note.title || "Untitled Note"
2554
+ ] }),
2555
+ /* @__PURE__ */ jsxs22("div", { className: "mt-1 flex items-center gap-3 text-xs text-fg-muted", children: [
2556
+ /* @__PURE__ */ jsxs22("span", { children: [
2557
+ "Updated ",
2558
+ note.updatedAt
2559
+ ] }),
2560
+ /* @__PURE__ */ jsxs22("span", { children: [
2561
+ "Created ",
2562
+ note.createdAt
2563
+ ] })
2564
+ ] })
2565
+ ] }),
2566
+ /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
2567
+ onTogglePin && /* @__PURE__ */ jsx30(
2568
+ Button,
2569
+ {
2570
+ size: "sm",
2571
+ variant: "ghost",
2572
+ onClick: () => onTogglePin(note.id),
2573
+ "aria-label": note.pinned ? "Unpin note" : "Pin note",
2574
+ children: note.pinned ? "Unpin" : "Pin"
2575
+ }
2576
+ ),
2577
+ onEdit && /* @__PURE__ */ jsx30(Button, { size: "sm", variant: "secondary", onClick: () => onEdit(note), children: "Edit" }),
2578
+ onDelete && /* @__PURE__ */ jsx30(Button, { size: "sm", variant: "danger", onClick: () => onDelete(note.id), children: "Delete" })
2579
+ ] })
2580
+ ] }),
2581
+ note.tags && note.tags.length > 0 && /* @__PURE__ */ jsx30("div", { className: "mt-3 flex flex-wrap gap-1.5 pb-2", children: note.tags.map((tag) => /* @__PURE__ */ jsx30(Badge, { variant: "neutral", children: tag }, tag)) }),
2582
+ /* @__PURE__ */ jsx30(
2583
+ "div",
2584
+ {
2585
+ "data-slot": "note-content",
2586
+ className: "yc-NoteView-content mt-4 flex-1 overflow-y-auto text-sm text-fg leading-relaxed whitespace-pre-wrap",
2587
+ children: note.content
2588
+ }
2589
+ )
2590
+ ]
2591
+ }
2592
+ );
2593
+ }
2594
+
2595
+ // src/calendar/Calendar.tsx
2596
+ import * as React23 from "react";
2597
+ import { jsx as jsx31, jsxs as jsxs23 } from "react/jsx-runtime";
2598
+ function Calendar({
2599
+ events,
2600
+ selectedDate = /* @__PURE__ */ new Date(),
2601
+ onSelectDate,
2602
+ onSelectEvent,
2603
+ viewMode = "month",
2604
+ onViewModeChange,
2605
+ className
2606
+ }) {
2607
+ const [currentDate, setCurrentDate] = React23.useState(selectedDate);
2608
+ const [currentView, setCurrentView] = React23.useState(viewMode);
2609
+ const activeView = onViewModeChange ? viewMode : currentView;
2610
+ const setView = (v) => {
2611
+ setCurrentView(v);
2612
+ onViewModeChange?.(v);
2613
+ };
2614
+ const handlePrev = () => {
2615
+ const next = new Date(currentDate);
2616
+ if (activeView === "month") {
2617
+ next.setMonth(next.getMonth() - 1);
2618
+ } else if (activeView === "week") {
2619
+ next.setDate(next.getDate() - 7);
2620
+ } else {
2621
+ next.setDate(next.getDate() - 1);
2622
+ }
2623
+ setCurrentDate(next);
2624
+ onSelectDate?.(next);
2625
+ };
2626
+ const handleNext = () => {
2627
+ const next = new Date(currentDate);
2628
+ if (activeView === "month") {
2629
+ next.setMonth(next.getMonth() + 1);
2630
+ } else if (activeView === "week") {
2631
+ next.setDate(next.getDate() + 7);
2632
+ } else {
2633
+ next.setDate(next.getDate() + 1);
2634
+ }
2635
+ setCurrentDate(next);
2636
+ onSelectDate?.(next);
2637
+ };
2638
+ const handleToday = () => {
2639
+ const today = /* @__PURE__ */ new Date();
2640
+ setCurrentDate(today);
2641
+ onSelectDate?.(today);
2642
+ };
2643
+ const monthName = currentDate.toLocaleString("default", { month: "long", year: "numeric" });
2644
+ const monthDays = React23.useMemo(() => {
2645
+ const year = currentDate.getFullYear();
2646
+ const month = currentDate.getMonth();
2647
+ const firstDayIndex = new Date(year, month, 1).getDay();
2648
+ const daysCount = new Date(year, month + 1, 0).getDate();
2649
+ const days = [];
2650
+ const prevMonthDaysCount = new Date(year, month, 0).getDate();
2651
+ for (let i = firstDayIndex - 1; i >= 0; i--) {
2652
+ days.push({
2653
+ dayNumber: prevMonthDaysCount - i,
2654
+ date: new Date(year, month - 1, prevMonthDaysCount - i),
2655
+ isCurrentMonth: false
2656
+ });
2657
+ }
2658
+ for (let i = 1; i <= daysCount; i++) {
2659
+ days.push({
2660
+ dayNumber: i,
2661
+ date: new Date(year, month, i),
2662
+ isCurrentMonth: true
2663
+ });
2664
+ }
2665
+ return days;
2666
+ }, [currentDate]);
2667
+ return /* @__PURE__ */ jsxs23(
2668
+ "div",
2669
+ {
2670
+ "data-slot": "calendar",
2671
+ "data-view": activeView,
2672
+ className: cn(
2673
+ "yc-Calendar-root flex flex-col rounded-xl border border-border bg-surface p-4 shadow-1",
2674
+ className
2675
+ ),
2676
+ children: [
2677
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-wrap items-center justify-between gap-3 pb-4 border-b border-border", children: [
2678
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
2679
+ /* @__PURE__ */ jsx31("h2", { className: "text-lg font-bold text-fg", children: monthName }),
2680
+ /* @__PURE__ */ jsx31(Button, { size: "sm", variant: "outline", onClick: handleToday, children: "Today" }),
2681
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1", children: [
2682
+ /* @__PURE__ */ jsx31(Button, { size: "sm", variant: "ghost", onClick: handlePrev, "aria-label": "Previous", children: "\u2039" }),
2683
+ /* @__PURE__ */ jsx31(Button, { size: "sm", variant: "ghost", onClick: handleNext, "aria-label": "Next", children: "\u203A" })
2684
+ ] })
2685
+ ] }),
2686
+ /* @__PURE__ */ jsx31(
2687
+ SegmentedControl,
2688
+ {
2689
+ size: "sm",
2690
+ value: activeView,
2691
+ onChange: (v) => setView(v),
2692
+ options: [
2693
+ { value: "month", label: "Month" },
2694
+ { value: "week", label: "Week" },
2695
+ { value: "agenda", label: "Agenda" }
2696
+ ]
2697
+ }
2698
+ )
2699
+ ] }),
2700
+ activeView === "month" && /* @__PURE__ */ jsxs23("div", { "data-slot": "month-view", className: "mt-4 flex flex-col", children: [
2701
+ /* @__PURE__ */ jsx31("div", { className: "grid grid-cols-7 text-center text-xs font-semibold text-fg-muted pb-2", children: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].map((d) => /* @__PURE__ */ jsx31("div", { className: "py-1", children: d }, d)) }),
2702
+ /* @__PURE__ */ jsx31("div", { className: "grid grid-cols-7 gap-px bg-border rounded-lg overflow-hidden border border-border", children: monthDays.map((d, idx) => {
2703
+ const dateStr = d.date.toISOString().split("T")[0];
2704
+ const dayEvents = events.filter((e) => {
2705
+ const s = typeof e.start === "string" ? e.start : e.start.toISOString();
2706
+ return s.startsWith(dateStr);
2707
+ });
2708
+ const hasConflict = dayEvents.some((e) => e.conflict);
2709
+ return /* @__PURE__ */ jsxs23(
2710
+ "div",
2711
+ {
2712
+ onClick: () => onSelectDate?.(d.date),
2713
+ className: cn(
2714
+ "min-h-[80px] p-1.5 flex flex-col justify-between cursor-pointer transition-colors",
2715
+ d.isCurrentMonth ? "bg-surface hover:bg-surface-2" : "bg-surface-2/50 text-fg-muted"
2716
+ ),
2717
+ children: [
2718
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
2719
+ /* @__PURE__ */ jsx31("span", { className: "text-xs font-medium", children: d.dayNumber }),
2720
+ hasConflict && /* @__PURE__ */ jsx31(Badge, { variant: "danger", className: "text-[10px] px-1 py-0", children: "Conflict" })
2721
+ ] }),
2722
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-1 mt-1", children: [
2723
+ dayEvents.slice(0, 2).map((ev) => /* @__PURE__ */ jsx31(
2724
+ "button",
2725
+ {
2726
+ type: "button",
2727
+ onClick: (e) => {
2728
+ e.stopPropagation();
2729
+ onSelectEvent?.(ev);
2730
+ },
2731
+ className: cn(
2732
+ "truncate rounded px-1 text-[11px] text-start font-medium",
2733
+ ev.conflict ? "bg-danger-bg text-danger-fg" : "bg-primary-subtle text-primary"
2734
+ ),
2735
+ children: ev.title
2736
+ },
2737
+ ev.id
2738
+ )),
2739
+ dayEvents.length > 2 && /* @__PURE__ */ jsxs23("span", { className: "text-[10px] text-fg-muted ps-1", children: [
2740
+ "+",
2741
+ dayEvents.length - 2,
2742
+ " more"
2743
+ ] })
2744
+ ] })
2745
+ ]
2746
+ },
2747
+ idx
2748
+ );
2749
+ }) })
2750
+ ] }),
2751
+ activeView === "week" && /* @__PURE__ */ jsx31("div", { "data-slot": "week-view", className: "mt-4 p-4 text-center text-sm text-fg-muted", children: /* @__PURE__ */ jsx31("div", { className: "grid grid-cols-7 gap-2", children: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].map((dayName, idx) => /* @__PURE__ */ jsxs23("div", { className: "rounded-lg border border-border p-2 bg-surface-2", children: [
2752
+ /* @__PURE__ */ jsx31("div", { className: "font-semibold text-fg text-xs pb-1", children: dayName }),
2753
+ /* @__PURE__ */ jsx31("div", { className: "space-y-1 mt-2", children: events.slice(0, 2).map((ev) => /* @__PURE__ */ jsx31(
2754
+ "div",
2755
+ {
2756
+ onClick: () => onSelectEvent?.(ev),
2757
+ className: cn(
2758
+ "cursor-pointer rounded p-1 text-[11px] truncate text-start",
2759
+ ev.conflict ? "bg-danger-bg text-danger-fg" : "bg-surface text-fg shadow-1"
2760
+ ),
2761
+ children: ev.title
2762
+ },
2763
+ ev.id
2764
+ )) })
2765
+ ] }, idx)) }) }),
2766
+ activeView === "agenda" && /* @__PURE__ */ jsx31("div", { "data-slot": "agenda-view", className: "mt-4 flex flex-col gap-2", children: events.length === 0 ? /* @__PURE__ */ jsx31("div", { className: "py-8 text-center text-sm text-fg-muted", children: "No scheduled events." }) : events.map((ev) => /* @__PURE__ */ jsxs23(
2767
+ "div",
2768
+ {
2769
+ onClick: () => onSelectEvent?.(ev),
2770
+ className: cn(
2771
+ "flex items-center justify-between rounded-lg border p-3 cursor-pointer hover:bg-surface-2 transition-colors",
2772
+ ev.conflict ? "border-danger-border bg-danger-bg/20" : "border-border bg-surface"
2773
+ ),
2774
+ children: [
2775
+ /* @__PURE__ */ jsxs23("div", { children: [
2776
+ /* @__PURE__ */ jsx31("h4", { className: "text-sm font-semibold text-fg", children: ev.title }),
2777
+ /* @__PURE__ */ jsxs23("p", { className: "text-xs text-fg-muted", children: [
2778
+ String(ev.start),
2779
+ " ",
2780
+ ev.location && `\u2022 ${ev.location}`
2781
+ ] })
2782
+ ] }),
2783
+ ev.conflict && /* @__PURE__ */ jsx31(Badge, { variant: "danger", children: "Conflict" })
2784
+ ]
2785
+ },
2786
+ ev.id
2787
+ )) })
2788
+ ]
2789
+ }
2790
+ );
2791
+ }
2792
+
2793
+ // src/calendar/ScheduleAgenda.tsx
2794
+ import { jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
2795
+ function ScheduleAgenda({
2796
+ events,
2797
+ onSelectEvent,
2798
+ className
2799
+ }) {
2800
+ return /* @__PURE__ */ jsx32(
2801
+ "div",
2802
+ {
2803
+ "data-slot": "schedule-agenda",
2804
+ className: cn("yc-ScheduleAgenda-root flex flex-col gap-3", className),
2805
+ children: events.length === 0 ? /* @__PURE__ */ jsx32("div", { className: "py-6 text-center text-sm text-fg-muted", children: "No scheduled agenda items." }) : events.map((event) => /* @__PURE__ */ jsxs24(
2806
+ "div",
2807
+ {
2808
+ onClick: () => onSelectEvent?.(event),
2809
+ "data-slot": "agenda-item",
2810
+ className: cn(
2811
+ "yc-ScheduleAgenda-item flex items-center justify-between rounded-lg border p-3 shadow-1 cursor-pointer transition-colors",
2812
+ event.conflict ? "border-danger-border bg-danger-bg/20" : "border-border bg-surface hover:bg-surface-2"
2813
+ ),
2814
+ children: [
2815
+ /* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-0.5", children: [
2816
+ /* @__PURE__ */ jsx32("span", { className: "text-sm font-semibold text-fg", children: event.title }),
2817
+ /* @__PURE__ */ jsxs24("span", { className: "text-xs text-fg-muted", children: [
2818
+ String(event.start),
2819
+ " ",
2820
+ event.location && `\u2022 ${event.location}`
2821
+ ] })
2822
+ ] }),
2823
+ event.conflict && /* @__PURE__ */ jsx32(Badge, { variant: "danger", children: "Conflict" })
2824
+ ]
2825
+ },
2826
+ event.id
2827
+ ))
2828
+ }
2829
+ );
2830
+ }
2831
+
2832
+ // src/calendar/Reminders.tsx
2833
+ import { jsx as jsx33, jsxs as jsxs25 } from "react/jsx-runtime";
2834
+ function Reminders({
2835
+ reminders,
2836
+ onComplete,
2837
+ onSnooze,
2838
+ className
2839
+ }) {
2840
+ return /* @__PURE__ */ jsx33(
2841
+ "div",
2842
+ {
2843
+ "data-slot": "reminders",
2844
+ className: cn("yc-Reminders-root flex flex-col gap-2", className),
2845
+ children: reminders.length === 0 ? /* @__PURE__ */ jsx33("div", { className: "py-6 text-center text-sm text-fg-muted", children: "No reminders pending." }) : reminders.map((reminder) => {
2846
+ const isDone = reminder.completed;
2847
+ return /* @__PURE__ */ jsxs25(
2848
+ "div",
2849
+ {
2850
+ "data-slot": "reminder-item",
2851
+ "data-completed": isDone ? "true" : void 0,
2852
+ className: cn(
2853
+ "yc-Reminders-item flex items-center justify-between rounded-lg border border-border bg-surface p-3 shadow-1 transition-opacity",
2854
+ isDone && "opacity-60"
2855
+ ),
2856
+ children: [
2857
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-3", children: [
2858
+ /* @__PURE__ */ jsx33(
2859
+ "input",
2860
+ {
2861
+ type: "checkbox",
2862
+ checked: isDone,
2863
+ onChange: (e) => onComplete?.(reminder.id, e.target.checked),
2864
+ className: "h-4 w-4 rounded border-border text-primary focus:ring-primary",
2865
+ "aria-label": `Mark ${reminder.title} as completed`
2866
+ }
2867
+ ),
2868
+ /* @__PURE__ */ jsxs25("div", { className: "flex flex-col", children: [
2869
+ /* @__PURE__ */ jsx33(
2870
+ "span",
2871
+ {
2872
+ className: cn(
2873
+ "text-sm font-medium text-fg",
2874
+ isDone && "line-through text-fg-muted"
2875
+ ),
2876
+ children: reminder.title
2877
+ }
2878
+ ),
2879
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2 text-xs text-fg-muted", children: [
2880
+ /* @__PURE__ */ jsxs25("span", { children: [
2881
+ "Due: ",
2882
+ reminder.dueAt
2883
+ ] }),
2884
+ reminder.rrule && /* @__PURE__ */ jsxs25(Badge, { variant: "neutral", className: "text-[10px] px-1 py-0", children: [
2885
+ "\u{1F504} ",
2886
+ reminder.rrule
2887
+ ] }),
2888
+ reminder.snoozedUntil && /* @__PURE__ */ jsxs25("span", { className: "text-warn-fg", children: [
2889
+ "Snoozed until ",
2890
+ reminder.snoozedUntil
2891
+ ] })
2892
+ ] })
2893
+ ] })
2894
+ ] }),
2895
+ !isDone && onSnooze && /* @__PURE__ */ jsx33(
2896
+ Button,
2897
+ {
2898
+ size: "sm",
2899
+ variant: "ghost",
2900
+ onClick: () => onSnooze(reminder.id, 15),
2901
+ className: "text-xs",
2902
+ children: "Snooze 15m"
2903
+ }
2904
+ )
2905
+ ]
2906
+ },
2907
+ reminder.id
2908
+ );
2909
+ })
2910
+ }
2911
+ );
2912
+ }
2913
+
2914
+ // src/calendar/Routines.tsx
2915
+ import { jsx as jsx34, jsxs as jsxs26 } from "react/jsx-runtime";
2916
+ function Routines({
2917
+ routines,
2918
+ onToggleActive,
2919
+ className
2920
+ }) {
2921
+ return /* @__PURE__ */ jsx34(
2922
+ "div",
2923
+ {
2924
+ "data-slot": "routines",
2925
+ className: cn("yc-Routines-root flex flex-col gap-2.5", className),
2926
+ children: routines.length === 0 ? /* @__PURE__ */ jsx34("div", { className: "py-6 text-center text-sm text-fg-muted", children: "No active routines configured." }) : routines.map((routine) => /* @__PURE__ */ jsxs26(
2927
+ "div",
2928
+ {
2929
+ "data-slot": "routine-item",
2930
+ className: "yc-Routines-item flex items-center justify-between rounded-lg border border-border bg-surface p-3 shadow-1",
2931
+ children: [
2932
+ /* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-1", children: [
2933
+ /* @__PURE__ */ jsx34("span", { className: "text-sm font-semibold text-fg", children: routine.title }),
2934
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2 text-xs text-fg-muted", children: [
2935
+ /* @__PURE__ */ jsx34(Badge, { variant: "neutral", children: routine.frequency }),
2936
+ /* @__PURE__ */ jsx34("span", { children: routine.timeOfDay }),
2937
+ routine.durationMinutes && /* @__PURE__ */ jsxs26("span", { children: [
2938
+ "(",
2939
+ routine.durationMinutes,
2940
+ " mins)"
2941
+ ] })
2942
+ ] })
2943
+ ] }),
2944
+ /* @__PURE__ */ jsxs26("label", { className: "relative inline-flex cursor-pointer items-center", children: [
2945
+ /* @__PURE__ */ jsx34(
2946
+ "input",
2947
+ {
2948
+ type: "checkbox",
2949
+ checked: routine.active,
2950
+ onChange: (e) => onToggleActive?.(routine.id, e.target.checked),
2951
+ className: "sr-only peer",
2952
+ "aria-label": `Toggle ${routine.title} routine`
2953
+ }
2954
+ ),
2955
+ /* @__PURE__ */ jsx34("div", { className: "h-6 w-11 rounded-full bg-surface-3 peer peer-checked:bg-primary peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-border after:border after:rounded-full after:h-5 after:w-5 after:transition-all" })
2956
+ ] })
2957
+ ]
2958
+ },
2959
+ routine.id
2960
+ ))
2961
+ }
2962
+ );
2963
+ }
2964
+
2965
+ // src/calendar/ActivityTimeline.tsx
2966
+ import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
2967
+ var statusColors = {
2968
+ info: "bg-info-fg",
2969
+ success: "bg-success-fg",
2970
+ warn: "bg-warn-fg",
2971
+ danger: "bg-danger-fg"
2972
+ };
2973
+ function ActivityTimeline({ events, className }) {
2974
+ return /* @__PURE__ */ jsx35(
2975
+ "div",
2976
+ {
2977
+ "data-slot": "activity-timeline",
2978
+ className: cn("yc-ActivityTimeline-root flex flex-col", className),
2979
+ children: events.length === 0 ? /* @__PURE__ */ jsx35("div", { className: "py-6 text-center text-sm text-fg-muted", children: "No timeline activities." }) : /* @__PURE__ */ jsx35("div", { className: "relative border-s border-border ms-3.5 space-y-6 my-2", children: events.map((ev) => /* @__PURE__ */ jsxs27(
2980
+ "div",
2981
+ {
2982
+ "data-slot": "timeline-item",
2983
+ className: "yc-ActivityTimeline-item relative ps-6",
2984
+ children: [
2985
+ /* @__PURE__ */ jsx35(
2986
+ "span",
2987
+ {
2988
+ className: cn(
2989
+ "absolute -start-1.5 top-1 h-3 w-3 rounded-full border-2 border-surface",
2990
+ statusColors[ev.status || "info"]
2991
+ )
2992
+ }
2993
+ ),
2994
+ /* @__PURE__ */ jsxs27("div", { className: "flex flex-col", children: [
2995
+ /* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between gap-2", children: [
2996
+ /* @__PURE__ */ jsx35("span", { className: "text-sm font-semibold text-fg", children: ev.title }),
2997
+ /* @__PURE__ */ jsx35("span", { className: "text-xs text-fg-muted", children: ev.timestamp })
2998
+ ] }),
2999
+ ev.description && /* @__PURE__ */ jsx35("p", { className: "mt-1 text-xs text-fg-muted leading-relaxed", children: ev.description })
3000
+ ] })
3001
+ ]
3002
+ },
3003
+ ev.id
3004
+ )) })
3005
+ }
3006
+ );
3007
+ }
3008
+
3009
+ // src/profiles/ProfileSwitcher.tsx
3010
+ import { jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
3011
+ function ProfileSwitcher({
3012
+ members,
3013
+ activeMemberId,
3014
+ onSelectMember,
3015
+ className
3016
+ }) {
3017
+ const activeMember = members.find((m) => m.id === activeMemberId) || members[0];
3018
+ return /* @__PURE__ */ jsx36(
3019
+ "div",
3020
+ {
3021
+ "data-slot": "profile-switcher",
3022
+ className: cn("yc-ProfileSwitcher-root inline-block", className),
3023
+ children: /* @__PURE__ */ jsxs28(Menu, { children: [
3024
+ /* @__PURE__ */ jsxs28(MenuTrigger, { className: "flex items-center gap-2 rounded-lg border border-border bg-surface px-2.5 py-1.5 shadow-1 hover:bg-surface-2 transition-colors", children: [
3025
+ /* @__PURE__ */ jsx36(Avatar, { size: "sm", children: activeMember?.avatarUrl ? /* @__PURE__ */ jsx36(AvatarImage, { src: activeMember.avatarUrl, alt: activeMember.displayName }) : /* @__PURE__ */ jsx36(AvatarFallback, { children: activeMember ? activeMember.displayName.substring(0, 2).toUpperCase() : "ME" }) }),
3026
+ /* @__PURE__ */ jsxs28("div", { className: "flex flex-col text-start", children: [
3027
+ /* @__PURE__ */ jsx36("span", { className: "text-xs font-semibold text-fg", children: activeMember ? activeMember.displayName : "Select Profile" }),
3028
+ activeMember?.relationship && /* @__PURE__ */ jsx36("span", { className: "text-[10px] text-fg-muted", children: activeMember.relationship })
3029
+ ] }),
3030
+ /* @__PURE__ */ jsx36("span", { className: "ms-1 text-xs text-fg-muted", children: "\u25BE" })
3031
+ ] }),
3032
+ /* @__PURE__ */ jsx36(MenuContent, { align: "start", children: members.map((member) => /* @__PURE__ */ jsxs28(
3033
+ MenuItem,
3034
+ {
3035
+ onClick: () => onSelectMember(member.id),
3036
+ className: cn(
3037
+ "flex items-center gap-2.5 py-2",
3038
+ member.id === activeMemberId && "bg-surface-2 font-semibold"
3039
+ ),
3040
+ children: [
3041
+ /* @__PURE__ */ jsx36(Avatar, { size: "sm", children: member.avatarUrl ? /* @__PURE__ */ jsx36(AvatarImage, { src: member.avatarUrl, alt: member.displayName }) : /* @__PURE__ */ jsx36(AvatarFallback, { children: member.displayName.substring(0, 2).toUpperCase() }) }),
3042
+ /* @__PURE__ */ jsxs28("div", { className: "flex flex-col text-start", children: [
3043
+ /* @__PURE__ */ jsx36("span", { className: "text-xs text-fg", children: member.displayName }),
3044
+ /* @__PURE__ */ jsx36("span", { className: "text-[10px] text-fg-muted", children: member.relationship || member.role })
3045
+ ] })
3046
+ ]
3047
+ },
3048
+ member.id
3049
+ )) })
3050
+ ] })
3051
+ }
3052
+ );
3053
+ }
3054
+
3055
+ // src/profiles/MemberCard.tsx
3056
+ import { jsx as jsx37, jsxs as jsxs29 } from "react/jsx-runtime";
3057
+ var roleBadgeVariant = {
3058
+ owner: "primary",
3059
+ steward: "info",
3060
+ member: "neutral",
3061
+ viewer: "warn"
3062
+ };
3063
+ function MemberCard({ member, onEdit, className }) {
3064
+ return /* @__PURE__ */ jsxs29(
3065
+ "div",
3066
+ {
3067
+ "data-slot": "member-card",
3068
+ className: cn(
3069
+ "yc-MemberCard-root flex items-center justify-between rounded-xl border border-border bg-surface p-4 shadow-1",
3070
+ className
3071
+ ),
3072
+ children: [
3073
+ /* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-3", children: [
3074
+ /* @__PURE__ */ jsx37(Avatar, { size: "md", children: member.avatarUrl ? /* @__PURE__ */ jsx37(AvatarImage, { src: member.avatarUrl, alt: member.displayName }) : /* @__PURE__ */ jsx37(AvatarFallback, { children: member.displayName.substring(0, 2).toUpperCase() }) }),
3075
+ /* @__PURE__ */ jsxs29("div", { className: "flex flex-col", children: [
3076
+ /* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-2", children: [
3077
+ /* @__PURE__ */ jsx37("span", { className: "text-sm font-bold text-fg", children: member.displayName }),
3078
+ /* @__PURE__ */ jsx37(Badge, { variant: roleBadgeVariant[member.role], children: member.role })
3079
+ ] }),
3080
+ member.relationship && /* @__PURE__ */ jsx37("span", { className: "text-xs text-fg-muted", children: member.relationship }),
3081
+ member.scopes && member.scopes.length > 0 && /* @__PURE__ */ jsx37("div", { className: "mt-1 flex flex-wrap gap-1", children: member.scopes.map((scope) => /* @__PURE__ */ jsx37(
3082
+ "span",
3083
+ {
3084
+ className: "rounded bg-surface-2 px-1.5 py-0.5 text-[10px] text-fg-muted",
3085
+ children: scope
3086
+ },
3087
+ scope
3088
+ )) })
3089
+ ] })
3090
+ ] }),
3091
+ onEdit && /* @__PURE__ */ jsx37(Button, { size: "sm", variant: "ghost", onClick: () => onEdit(member), children: "Edit" })
3092
+ ]
3093
+ }
3094
+ );
3095
+ }
3096
+
3097
+ // src/profiles/ProfileEditModal.tsx
3098
+ import * as React24 from "react";
3099
+ import { jsx as jsx38, jsxs as jsxs30 } from "react/jsx-runtime";
3100
+ function ProfileEditModal({
3101
+ member,
3102
+ open,
3103
+ onOpenChange,
3104
+ onSave
3105
+ }) {
3106
+ const [displayName, setDisplayName] = React24.useState(member?.displayName || "");
3107
+ const [relationship, setRelationship] = React24.useState(member?.relationship || "");
3108
+ const [role, setRole] = React24.useState(member?.role || "member");
3109
+ React24.useEffect(() => {
3110
+ if (member) {
3111
+ setDisplayName(member.displayName);
3112
+ setRelationship(member.relationship || "");
3113
+ setRole(member.role);
3114
+ }
3115
+ }, [member]);
3116
+ const handleSubmit = (e) => {
3117
+ e.preventDefault();
3118
+ if (!member) return;
3119
+ onSave({
3120
+ ...member,
3121
+ displayName,
3122
+ relationship,
3123
+ role
3124
+ });
3125
+ onOpenChange(false);
3126
+ };
3127
+ return /* @__PURE__ */ jsx38(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx38(DialogContent, { className: "yc-ProfileEditModal-content max-w-md", children: /* @__PURE__ */ jsxs30("form", { onSubmit: handleSubmit, "data-slot": "profile-edit-modal", children: [
3128
+ /* @__PURE__ */ jsx38(DialogHeader, { children: /* @__PURE__ */ jsx38(DialogTitle, { children: "Edit Profile" }) }),
3129
+ /* @__PURE__ */ jsxs30("div", { className: "space-y-4 py-4 text-xs", children: [
3130
+ /* @__PURE__ */ jsxs30("div", { children: [
3131
+ /* @__PURE__ */ jsx38("label", { className: "block font-medium text-fg mb-1", children: "Display Name" }),
3132
+ /* @__PURE__ */ jsx38(
3133
+ "input",
3134
+ {
3135
+ type: "text",
3136
+ required: true,
3137
+ value: displayName,
3138
+ onChange: (e) => setDisplayName(e.target.value),
3139
+ className: "w-full rounded-md border border-border bg-surface-2 p-2 text-sm text-fg focus:border-primary focus:outline-none"
3140
+ }
3141
+ )
3142
+ ] }),
3143
+ /* @__PURE__ */ jsxs30("div", { children: [
3144
+ /* @__PURE__ */ jsx38("label", { className: "block font-medium text-fg mb-1", children: "Relationship" }),
3145
+ /* @__PURE__ */ jsx38(
3146
+ "input",
3147
+ {
3148
+ type: "text",
3149
+ value: relationship,
3150
+ onChange: (e) => setRelationship(e.target.value),
3151
+ placeholder: "e.g. Self, Spouse, Child, Ward",
3152
+ className: "w-full rounded-md border border-border bg-surface-2 p-2 text-sm text-fg focus:border-primary focus:outline-none"
3153
+ }
3154
+ )
3155
+ ] }),
3156
+ /* @__PURE__ */ jsxs30("div", { children: [
3157
+ /* @__PURE__ */ jsx38("label", { className: "block font-medium text-fg mb-1", children: "Role" }),
3158
+ /* @__PURE__ */ jsxs30(
3159
+ "select",
3160
+ {
3161
+ value: role,
3162
+ onChange: (e) => setRole(e.target.value),
3163
+ className: "w-full rounded-md border border-border bg-surface-2 p-2 text-sm text-fg focus:border-primary focus:outline-none",
3164
+ children: [
3165
+ /* @__PURE__ */ jsx38("option", { value: "owner", children: "Owner" }),
3166
+ /* @__PURE__ */ jsx38("option", { value: "steward", children: "Steward" }),
3167
+ /* @__PURE__ */ jsx38("option", { value: "member", children: "Member" }),
3168
+ /* @__PURE__ */ jsx38("option", { value: "viewer", children: "Viewer" })
3169
+ ]
3170
+ }
3171
+ )
3172
+ ] })
3173
+ ] }),
3174
+ /* @__PURE__ */ jsxs30(DialogFooter, { className: "gap-2", children: [
3175
+ /* @__PURE__ */ jsx38(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx38(Button, { type: "button", variant: "ghost", size: "sm", children: "Cancel" }) }),
3176
+ /* @__PURE__ */ jsx38(Button, { type: "submit", variant: "primary", size: "sm", children: "Save Changes" })
3177
+ ] })
3178
+ ] }) }) });
3179
+ }
3180
+
3181
+ // src/profiles/RoleMatrix.tsx
3182
+ import { jsx as jsx39, jsxs as jsxs31 } from "react/jsx-runtime";
3183
+ function RoleMatrix({
3184
+ permissions,
3185
+ onChange,
3186
+ readOnly = false,
3187
+ className
3188
+ }) {
3189
+ const handleToggle = (domainIndex, field, val) => {
3190
+ if (readOnly || !onChange) return;
3191
+ const next = [...permissions];
3192
+ next[domainIndex] = {
3193
+ ...next[domainIndex],
3194
+ [field]: val
3195
+ };
3196
+ onChange(next);
3197
+ };
3198
+ return /* @__PURE__ */ jsx39(
3199
+ "div",
3200
+ {
3201
+ "data-slot": "role-matrix",
3202
+ className: cn(
3203
+ "yc-RoleMatrix-root overflow-x-auto rounded-xl border border-border bg-surface text-fg shadow-1",
3204
+ className
3205
+ ),
3206
+ children: /* @__PURE__ */ jsxs31("table", { className: "w-full text-start text-xs", children: [
3207
+ /* @__PURE__ */ jsx39("thead", { className: "border-b border-border bg-surface-2 text-fg-muted font-semibold", children: /* @__PURE__ */ jsxs31("tr", { children: [
3208
+ /* @__PURE__ */ jsx39("th", { className: "p-3 text-start", children: "Domain Scope" }),
3209
+ /* @__PURE__ */ jsx39("th", { className: "p-3 text-center", children: "Read" }),
3210
+ /* @__PURE__ */ jsx39("th", { className: "p-3 text-center", children: "Write" }),
3211
+ /* @__PURE__ */ jsx39("th", { className: "p-3 text-center", children: "Approve" })
3212
+ ] }) }),
3213
+ /* @__PURE__ */ jsx39("tbody", { className: "divide-y divide-border", children: permissions.map((perm, idx) => /* @__PURE__ */ jsxs31("tr", { className: "hover:bg-surface-2/50 transition-colors", children: [
3214
+ /* @__PURE__ */ jsx39("td", { className: "p-3 font-medium text-fg capitalize", children: perm.domain }),
3215
+ /* @__PURE__ */ jsx39("td", { className: "p-3 text-center", children: /* @__PURE__ */ jsx39(
3216
+ "input",
3217
+ {
3218
+ type: "checkbox",
3219
+ checked: perm.read,
3220
+ disabled: readOnly,
3221
+ onChange: (e) => handleToggle(idx, "read", e.target.checked),
3222
+ className: "h-4 w-4 rounded border-border text-primary focus:ring-primary disabled:opacity-50",
3223
+ "aria-label": `Read permission for ${perm.domain}`
3224
+ }
3225
+ ) }),
3226
+ /* @__PURE__ */ jsx39("td", { className: "p-3 text-center", children: /* @__PURE__ */ jsx39(
3227
+ "input",
3228
+ {
3229
+ type: "checkbox",
3230
+ checked: perm.write,
3231
+ disabled: readOnly,
3232
+ onChange: (e) => handleToggle(idx, "write", e.target.checked),
3233
+ className: "h-4 w-4 rounded border-border text-primary focus:ring-primary disabled:opacity-50",
3234
+ "aria-label": `Write permission for ${perm.domain}`
3235
+ }
3236
+ ) }),
3237
+ /* @__PURE__ */ jsx39("td", { className: "p-3 text-center", children: /* @__PURE__ */ jsx39(
3238
+ "input",
3239
+ {
3240
+ type: "checkbox",
3241
+ checked: perm.approve,
3242
+ disabled: readOnly,
3243
+ onChange: (e) => handleToggle(idx, "approve", e.target.checked),
3244
+ className: "h-4 w-4 rounded border-border text-primary focus:ring-primary disabled:opacity-50",
3245
+ "aria-label": `Approve permission for ${perm.domain}`
3246
+ }
3247
+ ) })
3248
+ ] }, perm.domain)) })
3249
+ ] })
3250
+ }
3251
+ );
3252
+ }
3253
+
3254
+ // src/profiles/ViewerInvite.tsx
3255
+ import * as React25 from "react";
3256
+ import { jsx as jsx40, jsxs as jsxs32 } from "react/jsx-runtime";
3257
+ function ViewerInvite({
3258
+ availableScopes = ["general", "notes", "calendar", "finances", "records"],
3259
+ onSendInvite,
3260
+ className
3261
+ }) {
3262
+ const [email, setEmail] = React25.useState("");
3263
+ const [selectedScopes, setSelectedScopes] = React25.useState(["general"]);
3264
+ const [expiresInDays, setExpiresInDays] = React25.useState(7);
3265
+ const [sent, setSent] = React25.useState(false);
3266
+ const [loading, setLoading] = React25.useState(false);
3267
+ const toggleScope = (scope) => {
3268
+ setSelectedScopes(
3269
+ (prev) => prev.includes(scope) ? prev.filter((s) => s !== scope) : [...prev, scope]
3270
+ );
3271
+ };
3272
+ const handleSubmit = async (e) => {
3273
+ e.preventDefault();
3274
+ if (!email) return;
3275
+ setLoading(true);
3276
+ try {
3277
+ await onSendInvite?.({
3278
+ email,
3279
+ role: "viewer",
3280
+ scopes: selectedScopes,
3281
+ expiresInDays
3282
+ });
3283
+ setSent(true);
3284
+ } finally {
3285
+ setLoading(false);
3286
+ }
3287
+ };
3288
+ return /* @__PURE__ */ jsxs32(
3289
+ "div",
3290
+ {
3291
+ "data-slot": "viewer-invite",
3292
+ className: cn(
3293
+ "yc-ViewerInvite-root rounded-xl border border-border bg-surface p-6 shadow-1 text-xs",
3294
+ className
3295
+ ),
3296
+ children: [
3297
+ /* @__PURE__ */ jsx40("h3", { className: "text-base font-bold text-fg", children: "Invite Viewer" }),
3298
+ /* @__PURE__ */ jsx40("p", { className: "mt-1 text-fg-muted leading-relaxed", children: "Grant time-limited, read-only access to selected record scopes." }),
3299
+ sent ? /* @__PURE__ */ jsxs32("div", { className: "mt-4 rounded-lg bg-success-bg/30 border border-success-border p-4 text-center", children: [
3300
+ /* @__PURE__ */ jsx40("span", { className: "font-semibold text-success-fg", children: "Invitation Sent!" }),
3301
+ /* @__PURE__ */ jsxs32("p", { className: "mt-1 text-fg-muted", children: [
3302
+ "An invitation link has been dispatched to ",
3303
+ email,
3304
+ "."
3305
+ ] }),
3306
+ /* @__PURE__ */ jsx40(
3307
+ Button,
3308
+ {
3309
+ size: "sm",
3310
+ variant: "ghost",
3311
+ className: "mt-3",
3312
+ onClick: () => {
3313
+ setSent(false);
3314
+ setEmail("");
3315
+ },
3316
+ children: "Invite Another"
3317
+ }
3318
+ )
3319
+ ] }) : /* @__PURE__ */ jsxs32("form", { onSubmit: handleSubmit, className: "mt-4 space-y-4", children: [
3320
+ /* @__PURE__ */ jsxs32("div", { children: [
3321
+ /* @__PURE__ */ jsx40("label", { className: "block font-medium text-fg mb-1", children: "Viewer Email Address" }),
3322
+ /* @__PURE__ */ jsx40(
3323
+ "input",
3324
+ {
3325
+ type: "email",
3326
+ required: true,
3327
+ value: email,
3328
+ onChange: (e) => setEmail(e.target.value),
3329
+ placeholder: "e.g. viewer@example.com",
3330
+ className: "w-full rounded-md border border-border bg-surface-2 p-2 text-sm text-fg focus:border-primary focus:outline-none"
3331
+ }
3332
+ )
3333
+ ] }),
3334
+ /* @__PURE__ */ jsxs32("div", { children: [
3335
+ /* @__PURE__ */ jsx40("label", { className: "block font-medium text-fg mb-1", children: "Allowed Scopes" }),
3336
+ /* @__PURE__ */ jsx40("div", { className: "flex flex-wrap gap-1.5 mt-1", children: availableScopes.map((scope) => /* @__PURE__ */ jsx40(
3337
+ Chip,
3338
+ {
3339
+ selected: selectedScopes.includes(scope),
3340
+ onClick: () => toggleScope(scope),
3341
+ children: scope
3342
+ },
3343
+ scope
3344
+ )) })
3345
+ ] }),
3346
+ /* @__PURE__ */ jsxs32("div", { children: [
3347
+ /* @__PURE__ */ jsx40("label", { className: "block font-medium text-fg mb-1", children: "Access Expiration" }),
3348
+ /* @__PURE__ */ jsxs32(
3349
+ "select",
3350
+ {
3351
+ value: expiresInDays,
3352
+ onChange: (e) => setExpiresInDays(Number(e.target.value)),
3353
+ className: "w-full rounded-md border border-border bg-surface-2 p-2 text-sm text-fg focus:border-primary focus:outline-none",
3354
+ children: [
3355
+ /* @__PURE__ */ jsx40("option", { value: 1, children: "24 hours" }),
3356
+ /* @__PURE__ */ jsx40("option", { value: 7, children: "7 days" }),
3357
+ /* @__PURE__ */ jsx40("option", { value: 30, children: "30 days" }),
3358
+ /* @__PURE__ */ jsx40("option", { value: 90, children: "90 days" })
3359
+ ]
3360
+ }
3361
+ )
3362
+ ] }),
3363
+ /* @__PURE__ */ jsx40(Button, { type: "submit", variant: "primary", size: "sm", loading, className: "w-full", children: "Send Secure Invitation" })
3364
+ ] })
3365
+ ]
3366
+ }
3367
+ );
3368
+ }
3369
+
3370
+ // src/profiles/ShareBundle.tsx
3371
+ import * as React26 from "react";
3372
+ import { jsx as jsx41, jsxs as jsxs33 } from "react/jsx-runtime";
3373
+ function ShareBundle({
3374
+ availableScopes = ["general", "notes", "calendar", "finances", "records"],
3375
+ onCreateBundle,
3376
+ className
3377
+ }) {
3378
+ const [name, setName] = React26.useState("");
3379
+ const [selectedScopes, setSelectedScopes] = React26.useState(["general"]);
3380
+ const [requiresPasscode, setRequiresPasscode] = React26.useState(false);
3381
+ const [bundleLink, setBundleLink] = React26.useState(null);
3382
+ const [loading, setLoading] = React26.useState(false);
3383
+ const toggleScope = (scope) => {
3384
+ setSelectedScopes(
3385
+ (prev) => prev.includes(scope) ? prev.filter((s) => s !== scope) : [...prev, scope]
3386
+ );
3387
+ };
3388
+ const handleCreate = async (e) => {
3389
+ e.preventDefault();
3390
+ if (!name) return;
3391
+ setLoading(true);
3392
+ try {
3393
+ const link = await onCreateBundle?.({
3394
+ name,
3395
+ scopes: selectedScopes,
3396
+ requiresPasscode
3397
+ });
3398
+ setBundleLink(typeof link === "string" ? link : "https://yarvelle.local/bundles/b7a9c3");
3399
+ } finally {
3400
+ setLoading(false);
3401
+ }
3402
+ };
3403
+ return /* @__PURE__ */ jsxs33(
3404
+ "div",
3405
+ {
3406
+ "data-slot": "share-bundle",
3407
+ className: cn(
3408
+ "yc-ShareBundle-root rounded-xl border border-border bg-surface p-6 shadow-1 text-xs",
3409
+ className
3410
+ ),
3411
+ children: [
3412
+ /* @__PURE__ */ jsx41("h3", { className: "text-base font-bold text-fg", children: "Create Share Bundle" }),
3413
+ /* @__PURE__ */ jsx41("p", { className: "mt-1 text-fg-muted leading-relaxed", children: "Package records into an encrypted export bundle." }),
3414
+ bundleLink ? /* @__PURE__ */ jsxs33("div", { className: "mt-4 rounded-lg bg-surface-2 border border-border p-4 text-center", children: [
3415
+ /* @__PURE__ */ jsx41("span", { className: "font-semibold text-fg", children: "Bundle Created!" }),
3416
+ /* @__PURE__ */ jsx41("p", { className: "mt-1 text-fg-muted", children: "Shareable bundle link:" }),
3417
+ /* @__PURE__ */ jsx41("div", { className: "mt-2 rounded bg-surface p-2 font-mono text-xs text-primary border border-border", children: bundleLink }),
3418
+ /* @__PURE__ */ jsx41(
3419
+ Button,
3420
+ {
3421
+ size: "sm",
3422
+ variant: "ghost",
3423
+ className: "mt-3",
3424
+ onClick: () => {
3425
+ setBundleLink(null);
3426
+ setName("");
3427
+ },
3428
+ children: "Create Another"
3429
+ }
3430
+ )
3431
+ ] }) : /* @__PURE__ */ jsxs33("form", { onSubmit: handleCreate, className: "mt-4 space-y-4", children: [
3432
+ /* @__PURE__ */ jsxs33("div", { children: [
3433
+ /* @__PURE__ */ jsx41("label", { className: "block font-medium text-fg mb-1", children: "Bundle Name" }),
3434
+ /* @__PURE__ */ jsx41(
3435
+ "input",
3436
+ {
3437
+ type: "text",
3438
+ required: true,
3439
+ value: name,
3440
+ onChange: (e) => setName(e.target.value),
3441
+ placeholder: "e.g. Annual Record Dossier",
3442
+ className: "w-full rounded-md border border-border bg-surface-2 p-2 text-sm text-fg focus:border-primary focus:outline-none"
3443
+ }
3444
+ )
3445
+ ] }),
3446
+ /* @__PURE__ */ jsxs33("div", { children: [
3447
+ /* @__PURE__ */ jsx41("label", { className: "block font-medium text-fg mb-1", children: "Included Scopes" }),
3448
+ /* @__PURE__ */ jsx41("div", { className: "flex flex-wrap gap-1.5 mt-1", children: availableScopes.map((scope) => /* @__PURE__ */ jsx41(
3449
+ Chip,
3450
+ {
3451
+ selected: selectedScopes.includes(scope),
3452
+ onClick: () => toggleScope(scope),
3453
+ children: scope
3454
+ },
3455
+ scope
3456
+ )) })
3457
+ ] }),
3458
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", children: [
3459
+ /* @__PURE__ */ jsx41(
3460
+ "input",
3461
+ {
3462
+ id: "passcode-opt",
3463
+ type: "checkbox",
3464
+ checked: requiresPasscode,
3465
+ onChange: (e) => setRequiresPasscode(e.target.checked),
3466
+ className: "h-4 w-4 rounded border-border text-primary focus:ring-primary"
3467
+ }
3468
+ ),
3469
+ /* @__PURE__ */ jsx41("label", { htmlFor: "passcode-opt", className: "font-medium text-fg cursor-pointer", children: "Protect bundle with passkey / PIN" })
3470
+ ] }),
3471
+ /* @__PURE__ */ jsx41(Button, { type: "submit", variant: "primary", size: "sm", loading, className: "w-full", children: "Generate Secure Bundle" })
3472
+ ] })
3473
+ ]
3474
+ }
3475
+ );
3476
+ }
3477
+
3478
+ // src/profiles/TeenHandoverBanner.tsx
3479
+ import { jsx as jsx42, jsxs as jsxs34 } from "react/jsx-runtime";
3480
+ function TeenHandoverBanner({
3481
+ memberName,
3482
+ handoverDate,
3483
+ onInitiateHandover,
3484
+ onDismiss,
3485
+ className
3486
+ }) {
3487
+ return /* @__PURE__ */ jsxs34(
3488
+ "div",
3489
+ {
3490
+ "data-slot": "teen-handover-banner",
3491
+ className: cn(
3492
+ "yc-TeenHandoverBanner-root flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 rounded-xl border border-warn-border bg-warn-bg/30 p-4 text-xs text-fg shadow-1",
3493
+ className
3494
+ ),
3495
+ children: [
3496
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-start gap-3", children: [
3497
+ /* @__PURE__ */ jsx42("span", { className: "text-warn-fg text-lg leading-none", children: "\u26A0\uFE0F" }),
3498
+ /* @__PURE__ */ jsxs34("div", { children: [
3499
+ /* @__PURE__ */ jsx42("h4", { className: "font-semibold text-fg", children: "Privacy & Age-of-Majority Transition" }),
3500
+ /* @__PURE__ */ jsxs34("p", { className: "mt-0.5 text-fg-muted", children: [
3501
+ /* @__PURE__ */ jsx42("span", { className: "font-medium text-fg", children: memberName }),
3502
+ " reaches transition age on",
3503
+ " ",
3504
+ /* @__PURE__ */ jsx42("span", { className: "font-medium text-fg", children: handoverDate }),
3505
+ ". Account stewardship and record privacy settings should be reviewed."
3506
+ ] })
3507
+ ] })
3508
+ ] }),
3509
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2 shrink-0", children: [
3510
+ onDismiss && /* @__PURE__ */ jsx42(Button, { size: "sm", variant: "ghost", onClick: onDismiss, children: "Dismiss" }),
3511
+ onInitiateHandover && /* @__PURE__ */ jsx42(Button, { size: "sm", variant: "outline", onClick: onInitiateHandover, children: "Review Privacy" })
3512
+ ] })
3513
+ ]
3514
+ }
3515
+ );
3516
+ }
3517
+
3518
+ // src/tasks/TaskItem.tsx
3519
+ import { jsx as jsx43, jsxs as jsxs35 } from "react/jsx-runtime";
3520
+ var priorityBadgeVariant = {
3521
+ low: "neutral",
3522
+ medium: "warn",
3523
+ high: "danger"
3524
+ };
3525
+ function TaskItem({
3526
+ task,
3527
+ onToggleComplete,
3528
+ onDelete,
3529
+ className
3530
+ }) {
3531
+ const isDone = task.completed;
3532
+ return /* @__PURE__ */ jsxs35(
3533
+ "div",
3534
+ {
3535
+ "data-slot": "task-item",
3536
+ "data-completed": isDone ? "true" : void 0,
3537
+ className: cn(
3538
+ "yc-TaskItem-root flex items-center justify-between rounded-lg border border-border bg-surface p-3 shadow-1 transition-all",
3539
+ isDone && "opacity-60",
3540
+ className
3541
+ ),
3542
+ children: [
3543
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-3", children: [
3544
+ /* @__PURE__ */ jsx43(
3545
+ "input",
3546
+ {
3547
+ type: "checkbox",
3548
+ checked: isDone,
3549
+ onChange: (e) => onToggleComplete?.(task.id, e.target.checked),
3550
+ className: "h-4 w-4 rounded border-border text-primary focus:ring-primary",
3551
+ "aria-label": `Mark task ${task.title} as ${isDone ? "incomplete" : "complete"}`
3552
+ }
3553
+ ),
3554
+ /* @__PURE__ */ jsxs35("div", { className: "flex flex-col", children: [
3555
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3556
+ /* @__PURE__ */ jsx43(
3557
+ "span",
3558
+ {
3559
+ className: cn(
3560
+ "text-sm font-medium text-fg",
3561
+ isDone && "line-through text-fg-muted"
3562
+ ),
3563
+ children: task.title
3564
+ }
3565
+ ),
3566
+ task.priority && /* @__PURE__ */ jsx43(Badge, { variant: priorityBadgeVariant[task.priority], className: "text-[10px] px-1 py-0", children: task.priority })
3567
+ ] }),
3568
+ (task.description || task.dueAt) && /* @__PURE__ */ jsxs35("div", { className: "mt-0.5 flex items-center gap-2 text-xs text-fg-muted", children: [
3569
+ task.description && /* @__PURE__ */ jsx43("span", { children: task.description }),
3570
+ task.dueAt && /* @__PURE__ */ jsxs35("span", { children: [
3571
+ "Due: ",
3572
+ task.dueAt
3573
+ ] })
3574
+ ] })
3575
+ ] })
3576
+ ] }),
3577
+ onDelete && /* @__PURE__ */ jsx43(
3578
+ "button",
3579
+ {
3580
+ type: "button",
3581
+ onClick: () => onDelete(task.id),
3582
+ className: "text-fg-muted hover:text-danger-fg text-xs p-1",
3583
+ "aria-label": `Delete task ${task.title}`,
3584
+ children: "\u2715"
3585
+ }
3586
+ )
3587
+ ]
3588
+ }
3589
+ );
3590
+ }
3591
+
3592
+ // src/tasks/TaskList.tsx
3593
+ import * as React27 from "react";
3594
+ import { jsx as jsx44, jsxs as jsxs36 } from "react/jsx-runtime";
3595
+ function TaskList({
3596
+ tasks,
3597
+ onToggleComplete,
3598
+ onAddTask,
3599
+ onDeleteTask,
3600
+ className,
3601
+ emptyTitle = "No tasks",
3602
+ emptyDescription = "You have no tasks in this view."
3603
+ }) {
3604
+ const [filter, setFilter] = React27.useState("all");
3605
+ const [newTitle, setNewTitle] = React27.useState("");
3606
+ const filtered = tasks.filter((t) => {
3607
+ if (filter === "active") return !t.completed;
3608
+ if (filter === "completed") return t.completed;
3609
+ return true;
3610
+ });
3611
+ const handleAdd = (e) => {
3612
+ e.preventDefault();
3613
+ const trimmed = newTitle.trim();
3614
+ if (!trimmed) return;
3615
+ onAddTask?.(trimmed);
3616
+ setNewTitle("");
3617
+ };
3618
+ return /* @__PURE__ */ jsxs36(
3619
+ "div",
3620
+ {
3621
+ "data-slot": "task-list",
3622
+ className: cn("yc-TaskList-root flex flex-col gap-3", className),
3623
+ children: [
3624
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-between gap-3", children: [
3625
+ /* @__PURE__ */ jsx44(
3626
+ SegmentedControl,
3627
+ {
3628
+ size: "sm",
3629
+ value: filter,
3630
+ onChange: (v) => setFilter(v),
3631
+ options: [
3632
+ { value: "all", label: "All" },
3633
+ { value: "active", label: "Active" },
3634
+ { value: "completed", label: "Completed" }
3635
+ ]
3636
+ }
3637
+ ),
3638
+ /* @__PURE__ */ jsxs36("span", { className: "text-xs text-fg-muted", children: [
3639
+ tasks.filter((t) => !t.completed).length,
3640
+ " remaining"
3641
+ ] })
3642
+ ] }),
3643
+ onAddTask && /* @__PURE__ */ jsxs36("form", { onSubmit: handleAdd, className: "flex gap-2", children: [
3644
+ /* @__PURE__ */ jsx44(
3645
+ "input",
3646
+ {
3647
+ type: "text",
3648
+ value: newTitle,
3649
+ onChange: (e) => setNewTitle(e.target.value),
3650
+ placeholder: "Add a new task...",
3651
+ className: "flex-1 rounded-lg border border-border bg-surface-2 p-2 text-sm text-fg placeholder:text-fg-muted focus:border-primary focus:outline-none"
3652
+ }
3653
+ ),
3654
+ /* @__PURE__ */ jsx44(Button, { type: "submit", variant: "primary", size: "sm", children: "Add" })
3655
+ ] }),
3656
+ filtered.length === 0 ? /* @__PURE__ */ jsx44(EmptyState, { title: emptyTitle, description: emptyDescription }) : /* @__PURE__ */ jsx44("div", { className: "flex flex-col gap-2", children: filtered.map((task) => /* @__PURE__ */ jsx44(
3657
+ TaskItem,
3658
+ {
3659
+ task,
3660
+ onToggleComplete,
3661
+ onDelete: onDeleteTask
3662
+ },
3663
+ task.id
3664
+ )) })
3665
+ ]
3666
+ }
3667
+ );
3668
+ }
3669
+
3670
+ // src/notifications/NotificationCenter.tsx
3671
+ import { jsx as jsx45, jsxs as jsxs37 } from "react/jsx-runtime";
3672
+ var levelBadgeVariant2 = {
3673
+ info: "info",
3674
+ warn: "warn",
3675
+ danger: "danger",
3676
+ success: "success"
3677
+ };
3678
+ function NotificationCenter({
3679
+ notifications,
3680
+ onMarkAllRead,
3681
+ onDismiss,
3682
+ onSelectNotification,
3683
+ className
3684
+ }) {
3685
+ const unreadCount = notifications.filter((n) => !n.read).length;
3686
+ return /* @__PURE__ */ jsx45(
3687
+ "div",
3688
+ {
3689
+ "data-slot": "notification-center",
3690
+ className: cn("yc-NotificationCenter-root inline-block", className),
3691
+ children: /* @__PURE__ */ jsxs37(Popover, { children: [
3692
+ /* @__PURE__ */ jsxs37(PopoverTrigger, { className: "relative flex items-center justify-center p-2 rounded-lg border border-border bg-surface hover:bg-surface-2 transition-colors", children: [
3693
+ /* @__PURE__ */ jsx45("span", { className: "text-base", role: "img", "aria-label": "Notifications", children: "\u{1F514}" }),
3694
+ unreadCount > 0 && /* @__PURE__ */ jsx45("span", { className: "absolute -top-1 -end-1 flex h-4 w-4 items-center justify-center rounded-full bg-danger-fg text-[10px] font-bold text-white", children: unreadCount > 9 ? "9+" : unreadCount })
3695
+ ] }),
3696
+ /* @__PURE__ */ jsxs37(PopoverContent, { align: "end", className: "w-80 p-0 shadow-3", children: [
3697
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center justify-between border-b border-border p-3", children: [
3698
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2", children: [
3699
+ /* @__PURE__ */ jsx45("span", { className: "font-semibold text-sm text-fg", children: "Notifications" }),
3700
+ unreadCount > 0 && /* @__PURE__ */ jsxs37(Badge, { variant: "primary", children: [
3701
+ unreadCount,
3702
+ " new"
3703
+ ] })
3704
+ ] }),
3705
+ unreadCount > 0 && onMarkAllRead && /* @__PURE__ */ jsx45(
3706
+ "button",
3707
+ {
3708
+ type: "button",
3709
+ onClick: onMarkAllRead,
3710
+ className: "text-xs text-primary hover:underline font-medium",
3711
+ children: "Mark all read"
3712
+ }
3713
+ )
3714
+ ] }),
3715
+ /* @__PURE__ */ jsx45("div", { className: "max-h-80 overflow-y-auto divide-y divide-border", children: notifications.length === 0 ? /* @__PURE__ */ jsx45("div", { className: "p-6 text-center text-xs text-fg-muted", children: "No notifications right now." }) : notifications.map((n) => /* @__PURE__ */ jsxs37(
3716
+ "div",
3717
+ {
3718
+ onClick: () => onSelectNotification?.(n),
3719
+ "data-slot": "notification-item",
3720
+ "data-read": n.read ? "true" : void 0,
3721
+ className: cn(
3722
+ "flex items-start justify-between p-3 transition-colors text-start cursor-pointer",
3723
+ n.read ? "bg-surface opacity-75" : "bg-surface-2/60"
3724
+ ),
3725
+ children: [
3726
+ /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5 flex-1 pe-2", children: [
3727
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-1.5", children: [
3728
+ n.level && /* @__PURE__ */ jsx45(Badge, { variant: levelBadgeVariant2[n.level], className: "text-[9px] px-1 py-0", children: n.level }),
3729
+ /* @__PURE__ */ jsx45("span", { className: "font-medium text-xs text-fg", children: n.title })
3730
+ ] }),
3731
+ n.description && /* @__PURE__ */ jsx45("p", { className: "text-[11px] text-fg-muted line-clamp-2", children: n.description }),
3732
+ /* @__PURE__ */ jsx45("span", { className: "text-[10px] text-fg-muted mt-1", children: n.timestamp })
3733
+ ] }),
3734
+ onDismiss && /* @__PURE__ */ jsx45(
3735
+ "button",
3736
+ {
3737
+ type: "button",
3738
+ onClick: (e) => {
3739
+ e.stopPropagation();
3740
+ onDismiss(n.id);
3741
+ },
3742
+ className: "text-fg-muted hover:text-fg text-xs p-1",
3743
+ "aria-label": "Dismiss notification",
3744
+ children: "\u2715"
3745
+ }
3746
+ )
3747
+ ]
3748
+ },
3749
+ n.id
3750
+ )) })
3751
+ ] })
3752
+ ] })
3753
+ }
3754
+ );
3755
+ }
3756
+
3757
+ // src/settings/SettingsLayout.tsx
3758
+ import * as React29 from "react";
3759
+
3760
+ // src/slots/SlotRenderer.tsx
3761
+ import { useEffect as useEffect7, useState as useState22 } from "react";
3762
+ import { Fragment as Fragment3, jsx as jsx46, jsxs as jsxs38 } from "react/jsx-runtime";
3763
+ var SlotRenderer = ({
3764
+ contribution,
3765
+ slotProps,
3766
+ fallback = null
3767
+ }) => {
3768
+ const [LoadedComp, setLoadedComp] = useState22(() => contribution.component ?? null);
3769
+ const [error, setError] = useState22(null);
3770
+ useEffect7(() => {
3771
+ let cancelled = false;
3772
+ if (contribution.component) {
3773
+ setLoadedComp(() => contribution.component ?? null);
3774
+ return;
3775
+ }
3776
+ if (contribution.load) {
3777
+ contribution.load().then((mod) => {
3778
+ if (!cancelled) {
3779
+ setLoadedComp(() => mod.default);
3780
+ }
3781
+ }).catch((err) => {
3782
+ if (!cancelled) {
3783
+ setError(err instanceof Error ? err : new Error(String(err)));
3784
+ }
3785
+ });
3786
+ }
3787
+ return () => {
3788
+ cancelled = true;
3789
+ };
3790
+ }, [contribution]);
3791
+ if (error) {
3792
+ return /* @__PURE__ */ jsxs38("div", { className: "yc-SlotRenderer-error text-danger text-sm p-4", "data-slot": "error", children: [
3793
+ "Failed to load slot: ",
3794
+ contribution.id
3795
+ ] });
3796
+ }
3797
+ if (!LoadedComp) {
3798
+ return /* @__PURE__ */ jsx46(Fragment3, { children: fallback });
3799
+ }
3800
+ return /* @__PURE__ */ jsx46("div", { className: "yc-SlotRenderer-root", "data-slot": "root", "data-pack": contribution.pack, "data-contribution": contribution.id, children: /* @__PURE__ */ jsx46(LoadedComp, { ...slotProps }) });
3801
+ };
3802
+
3803
+ // src/settings/SettingsLayout.tsx
3804
+ import { jsx as jsx47, jsxs as jsxs39 } from "react/jsx-runtime";
3805
+ function SettingsLayout({
3806
+ sections,
3807
+ activeSectionId,
3808
+ onSelectSection,
3809
+ contributions = [],
3810
+ slotProps,
3811
+ children,
3812
+ className
3813
+ }) {
3814
+ const mergedSections = React29.useMemo(() => {
3815
+ const list = [...sections];
3816
+ const slotSections = contributions.filter((c) => c.slot === "settings.section").map((c) => ({
3817
+ id: c.id,
3818
+ title: c.title,
3819
+ order: c.order ?? 50,
3820
+ slotContribution: c
3821
+ }));
3822
+ list.push(...slotSections);
3823
+ return list.sort((a, b) => (a.order ?? 50) - (b.order ?? 50));
3824
+ }, [sections, contributions]);
3825
+ const [selectedId, setSelectedId] = React29.useState(
3826
+ activeSectionId || (mergedSections[0]?.id ?? "")
3827
+ );
3828
+ const currentId = activeSectionId !== void 0 ? activeSectionId : selectedId;
3829
+ const currentSection = mergedSections.find((s) => s.id === currentId) || mergedSections[0];
3830
+ const handleSelect = (id) => {
3831
+ setSelectedId(id);
3832
+ onSelectSection?.(id);
3833
+ };
3834
+ return /* @__PURE__ */ jsxs39(
3835
+ "div",
3836
+ {
3837
+ "data-slot": "settings-layout",
3838
+ className: cn(
3839
+ "yc-SettingsLayout-root flex flex-col md:flex-row gap-6 w-full max-w-6xl mx-auto p-4 md:p-6",
3840
+ className
3841
+ ),
3842
+ children: [
3843
+ /* @__PURE__ */ jsxs39(
3844
+ "nav",
3845
+ {
3846
+ "data-slot": "nav",
3847
+ className: "yc-SettingsLayout-nav w-full md:w-64 shrink-0 flex flex-col gap-1",
3848
+ "aria-label": "Settings navigation",
3849
+ children: [
3850
+ /* @__PURE__ */ jsx47("h2", { className: "text-lg font-bold text-fg px-3 pb-3", children: "Settings" }),
3851
+ mergedSections.map((sec) => {
3852
+ const isActive = sec.id === currentId;
3853
+ return /* @__PURE__ */ jsxs39(
3854
+ "button",
3855
+ {
3856
+ type: "button",
3857
+ onClick: () => handleSelect(sec.id),
3858
+ "data-slot": "nav-item",
3859
+ "data-active": isActive ? "true" : void 0,
3860
+ className: cn(
3861
+ "flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium transition-colors text-start",
3862
+ isActive ? "bg-surface-2 text-fg font-semibold shadow-1" : "text-fg-muted hover:bg-surface-2/60 hover:text-fg"
3863
+ ),
3864
+ children: [
3865
+ sec.icon && /* @__PURE__ */ jsx47("span", { className: "inline-flex shrink-0", children: sec.icon }),
3866
+ /* @__PURE__ */ jsx47("span", { className: "truncate", children: sec.title })
3867
+ ]
3868
+ },
3869
+ sec.id
3870
+ );
3871
+ })
3872
+ ]
3873
+ }
3874
+ ),
3875
+ /* @__PURE__ */ jsx47(
3876
+ "main",
3877
+ {
3878
+ "data-slot": "content",
3879
+ className: "yc-SettingsLayout-content flex-1 rounded-xl border border-border bg-surface p-6 shadow-1",
3880
+ children: currentSection && /* @__PURE__ */ jsxs39("div", { children: [
3881
+ /* @__PURE__ */ jsxs39("div", { className: "border-b border-border pb-4 mb-6", children: [
3882
+ /* @__PURE__ */ jsx47("h3", { className: "text-xl font-bold text-fg", children: currentSection.title }),
3883
+ currentSection.description && /* @__PURE__ */ jsx47("p", { className: "mt-1 text-sm text-fg-muted", children: currentSection.description })
3884
+ ] }),
3885
+ currentSection.slotContribution && slotProps ? /* @__PURE__ */ jsx47(
3886
+ SlotRenderer,
3887
+ {
3888
+ contribution: currentSection.slotContribution,
3889
+ slotProps
3890
+ }
3891
+ ) : currentSection.component ? /* @__PURE__ */ jsx47(currentSection.component, {}) : children
3892
+ ] })
3893
+ }
3894
+ )
3895
+ ]
3896
+ }
3897
+ );
3898
+ }
3899
+
3900
+ // src/settings/SettingsSectionSlotRenderer.tsx
3901
+ import { jsx as jsx48, jsxs as jsxs40 } from "react/jsx-runtime";
3902
+ function SettingsSectionSlotRenderer({
3903
+ contributions,
3904
+ slotProps,
3905
+ className
3906
+ }) {
3907
+ const sectionSlots = contributions.filter((c) => c.slot === "settings.section");
3908
+ return /* @__PURE__ */ jsx48(
3909
+ "div",
3910
+ {
3911
+ "data-slot": "settings-section-slot-renderer",
3912
+ className: cn("yc-SettingsSectionSlotRenderer-root space-y-6", className),
3913
+ children: sectionSlots.map((c) => /* @__PURE__ */ jsxs40(
3914
+ "div",
3915
+ {
3916
+ className: "rounded-xl border border-border bg-surface p-6 shadow-1",
3917
+ "data-slot": "slot-section",
3918
+ children: [
3919
+ /* @__PURE__ */ jsx48("div", { className: "border-b border-border pb-3 mb-4", children: /* @__PURE__ */ jsx48("h3", { className: "text-base font-semibold text-fg", children: c.title }) }),
3920
+ /* @__PURE__ */ jsx48(SlotRenderer, { contribution: c, slotProps })
3921
+ ]
3922
+ },
3923
+ c.id
3924
+ ))
3925
+ }
3926
+ );
3927
+ }
3928
+
3929
+ // src/shell/AppRail.tsx
3930
+ import * as React30 from "react";
3931
+ import { jsx as jsx49, jsxs as jsxs41 } from "react/jsx-runtime";
3932
+ function AppRail({
3933
+ items,
3934
+ contributions = [],
3935
+ activeItemId,
3936
+ onSelectItem,
3937
+ brand,
3938
+ footer,
3939
+ collapsed = false,
3940
+ className
3941
+ }) {
3942
+ const allItems = React30.useMemo(() => {
3943
+ const list = [...items];
3944
+ const slotItems = contributions.filter((c) => c.slot === "sidebar.item").map((c) => ({
3945
+ id: c.id,
3946
+ label: c.title,
3947
+ route: c.route,
3948
+ slotContribution: c
3949
+ }));
3950
+ list.push(...slotItems);
3951
+ return list;
3952
+ }, [items, contributions]);
3953
+ return /* @__PURE__ */ jsxs41(
3954
+ "aside",
3955
+ {
3956
+ "data-slot": "app-rail",
3957
+ "data-collapsed": collapsed ? "true" : void 0,
3958
+ className: cn(
3959
+ "yc-AppRail-root flex flex-col justify-between border-e border-border bg-surface text-fg transition-all duration-normal",
3960
+ collapsed ? "w-16" : "w-64",
3961
+ className
3962
+ ),
3963
+ children: [
3964
+ /* @__PURE__ */ jsxs41("div", { className: "flex flex-col", children: [
3965
+ brand && /* @__PURE__ */ jsx49("div", { className: "flex items-center gap-3 border-b border-border p-4", "data-slot": "brand", children: brand }),
3966
+ /* @__PURE__ */ jsx49("nav", { className: "flex flex-col gap-1 p-2", "aria-label": "Main Navigation", children: allItems.map((item) => {
3967
+ const isActive = item.active || item.id === activeItemId;
3968
+ return /* @__PURE__ */ jsxs41(
3969
+ "button",
3970
+ {
3971
+ type: "button",
3972
+ onClick: () => {
3973
+ item.onClick?.();
3974
+ onSelectItem?.(item);
3975
+ },
3976
+ "data-slot": "rail-item",
3977
+ "data-active": isActive ? "true" : void 0,
3978
+ className: cn(
3979
+ "flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors text-start",
3980
+ collapsed && "justify-center px-2",
3981
+ isActive ? "bg-surface-2 text-primary font-semibold shadow-1" : "text-fg-muted hover:bg-surface-2/60 hover:text-fg"
3982
+ ),
3983
+ title: collapsed ? item.label : void 0,
3984
+ children: [
3985
+ item.icon && /* @__PURE__ */ jsx49("span", { className: "inline-flex shrink-0", children: item.icon }),
3986
+ !collapsed && /* @__PURE__ */ jsx49("span", { className: "truncate flex-1", children: item.label }),
3987
+ !collapsed && item.badge !== void 0 && /* @__PURE__ */ jsx49("span", { className: "rounded-full bg-primary-subtle px-1.5 py-0.5 text-[10px] font-bold text-primary", children: item.badge })
3988
+ ]
3989
+ },
3990
+ item.id
3991
+ );
3992
+ }) })
3993
+ ] }),
3994
+ footer && /* @__PURE__ */ jsx49("div", { className: "border-t border-border p-3", "data-slot": "footer", children: footer })
3995
+ ]
3996
+ }
3997
+ );
3998
+ }
3999
+
4000
+ // src/shell/MobileTopBar.tsx
4001
+ import { jsx as jsx50, jsxs as jsxs42 } from "react/jsx-runtime";
4002
+ function MobileTopBar({
4003
+ title,
4004
+ startSlot,
4005
+ endSlot,
4006
+ leftSlot,
4007
+ rightSlot,
4008
+ className
4009
+ }) {
4010
+ const leading = startSlot || leftSlot;
4011
+ const trailing = endSlot || rightSlot;
4012
+ return /* @__PURE__ */ jsxs42(
4013
+ "header",
4014
+ {
4015
+ "data-slot": "mobile-top-bar",
4016
+ className: cn(
4017
+ "yc-MobileTopBar-root flex items-center justify-between border-b border-border bg-surface px-4 py-2.5 text-fg md:hidden z-30 sticky top-0",
4018
+ className
4019
+ ),
4020
+ children: [
4021
+ /* @__PURE__ */ jsx50("div", { className: "flex items-center gap-2", "data-slot": "start-slot", children: leading }),
4022
+ title && /* @__PURE__ */ jsx50("h1", { className: "text-base font-bold text-fg truncate text-center flex-1 px-2", "data-slot": "title", children: title }),
4023
+ /* @__PURE__ */ jsx50("div", { className: "flex items-center gap-2", "data-slot": "end-slot", children: trailing })
4024
+ ]
4025
+ }
4026
+ );
4027
+ }
4028
+
4029
+ // src/shell/MobileTabBar.tsx
4030
+ import { jsx as jsx51, jsxs as jsxs43 } from "react/jsx-runtime";
4031
+ function MobileTabBar({
4032
+ items,
4033
+ activeItemId,
4034
+ onSelectItem,
4035
+ className
4036
+ }) {
4037
+ return /* @__PURE__ */ jsx51(
4038
+ "nav",
4039
+ {
4040
+ "data-slot": "mobile-tab-bar",
4041
+ className: cn(
4042
+ "yc-MobileTabBar-root fixed bottom-0 inset-x-0 z-30 flex items-center justify-around border-t border-border bg-surface px-2 py-1 md:hidden",
4043
+ className
4044
+ ),
4045
+ "aria-label": "Mobile Navigation",
4046
+ children: items.map((item) => {
4047
+ const isActive = item.active || item.id === activeItemId;
4048
+ return /* @__PURE__ */ jsxs43(
4049
+ "button",
4050
+ {
4051
+ type: "button",
4052
+ onClick: () => {
4053
+ item.onClick?.();
4054
+ onSelectItem?.(item);
4055
+ },
4056
+ "data-slot": "tab-item",
4057
+ "data-active": isActive ? "true" : void 0,
4058
+ className: cn(
4059
+ "flex flex-col items-center justify-center flex-1 py-1.5 px-1 text-[11px] font-medium transition-colors min-h-[44px]",
4060
+ isActive ? "text-primary font-bold" : "text-fg-muted hover:text-fg"
4061
+ ),
4062
+ children: [
4063
+ item.icon && /* @__PURE__ */ jsx51("span", { className: "text-lg leading-none mb-0.5", children: item.icon }),
4064
+ /* @__PURE__ */ jsx51("span", { className: "truncate max-w-[64px]", children: item.label })
4065
+ ]
4066
+ },
4067
+ item.id
4068
+ );
4069
+ })
4070
+ }
4071
+ );
4072
+ }
4073
+
4074
+ // src/shell/AppLayout.tsx
4075
+ import { jsx as jsx52, jsxs as jsxs44 } from "react/jsx-runtime";
4076
+ function AppLayout({
4077
+ items,
4078
+ contributions = [],
4079
+ activeItemId,
4080
+ onSelectItem,
4081
+ brand,
4082
+ railFooter,
4083
+ mobileTopLeft,
4084
+ mobileTopRight,
4085
+ children,
4086
+ className
4087
+ }) {
4088
+ const activeItem = items.find((i) => i.id === activeItemId) || items[0];
4089
+ return /* @__PURE__ */ jsxs44(
4090
+ "div",
4091
+ {
4092
+ "data-slot": "app-layout",
4093
+ className: cn(
4094
+ "yc-AppLayout-root flex h-screen w-screen overflow-hidden bg-bg text-fg",
4095
+ className
4096
+ ),
4097
+ children: [
4098
+ /* @__PURE__ */ jsx52("div", { className: "hidden md:flex h-full shrink-0", children: /* @__PURE__ */ jsx52(
4099
+ AppRail,
4100
+ {
4101
+ items,
4102
+ contributions,
4103
+ activeItemId,
4104
+ onSelectItem,
4105
+ brand,
4106
+ footer: railFooter
4107
+ }
4108
+ ) }),
4109
+ /* @__PURE__ */ jsxs44("div", { className: "flex flex-1 flex-col h-full overflow-hidden", children: [
4110
+ /* @__PURE__ */ jsx52(
4111
+ MobileTopBar,
4112
+ {
4113
+ title: activeItem?.label,
4114
+ leftSlot: mobileTopLeft,
4115
+ rightSlot: mobileTopRight
4116
+ }
4117
+ ),
4118
+ /* @__PURE__ */ jsx52(
4119
+ "main",
4120
+ {
4121
+ "data-slot": "main-content",
4122
+ className: "yc-AppLayout-content flex-1 overflow-y-auto pb-16 md:pb-0",
4123
+ children
4124
+ }
4125
+ ),
4126
+ /* @__PURE__ */ jsx52(
4127
+ MobileTabBar,
4128
+ {
4129
+ items: items.slice(0, 5),
4130
+ activeItemId,
4131
+ onSelectItem
4132
+ }
4133
+ )
4134
+ ] })
4135
+ ]
4136
+ }
4137
+ );
4138
+ }
4139
+
4140
+ // src/slots/types.ts
4141
+ function definePackUi(def) {
4142
+ return {
4143
+ pack: def.pack,
4144
+ contributions: def.contributions,
4145
+ messages: def.messages
4146
+ };
4147
+ }
4148
+ function matchesScopePattern(pattern, target) {
4149
+ if (pattern === "*" || pattern === target) return true;
4150
+ if (pattern.endsWith(".*")) {
4151
+ const prefix = pattern.slice(0, -2);
4152
+ return target === prefix || target.startsWith(`${prefix}.`);
4153
+ }
4154
+ return false;
4155
+ }
4156
+ function isScopeSatisfied(requiredScope, activeScopes) {
4157
+ return activeScopes.some((active) => matchesScopePattern(active, requiredScope));
4158
+ }
4159
+ function filterSlotContributions(contributions, options = {}) {
4160
+ const { slot, enabledPacks, activeScopes, hiddenPanels = [], audience } = options;
4161
+ return contributions.filter((c) => {
4162
+ if (slot && c.slot !== slot) return false;
4163
+ if (enabledPacks && !enabledPacks.includes(c.pack)) return false;
4164
+ if (hiddenPanels.includes(c.id)) return false;
4165
+ if (audience && c.audiences && c.audiences.length > 0 && !c.audiences.includes(audience)) {
4166
+ return false;
4167
+ }
4168
+ if (activeScopes && c.requiredScopes && c.requiredScopes.length > 0) {
4169
+ const allSatisfied = c.requiredScopes.every((req) => isScopeSatisfied(req, activeScopes));
4170
+ if (!allSatisfied) return false;
4171
+ }
4172
+ return true;
4173
+ }).sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
4174
+ }
4175
+
4176
+ // src/provider/UiProvider.tsx
4177
+ import { createContext as createContext8, useContext as useContext8, useEffect as useEffect8, useState as useState24 } from "react";
4178
+ import { jsx as jsx53 } from "react/jsx-runtime";
4179
+ var defaultI18n = {
4180
+ locale: "en-US",
4181
+ t: (_id, defaultText) => defaultText || _id
4182
+ };
4183
+ var UiContext = createContext8({
4184
+ theme: "system",
4185
+ resolvedTheme: "light",
4186
+ setTheme: () => {
4187
+ },
4188
+ product: { name: "Yarvelle" },
4189
+ storageNamespace: "yarvelle",
4190
+ i18n: defaultI18n
4191
+ });
4192
+ var UiProvider = ({
4193
+ children,
4194
+ defaultTheme = "system",
4195
+ product = { name: "Yarvelle" },
4196
+ storageNamespace = "yarvelle",
4197
+ locale = "en-US",
4198
+ messages = {}
4199
+ }) => {
4200
+ const [theme, setThemeState] = useState24(defaultTheme);
4201
+ const [resolvedTheme, setResolvedTheme] = useState24("light");
4202
+ useEffect8(() => {
4203
+ const root = document.documentElement;
4204
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
4205
+ const updateTheme = () => {
4206
+ let isDark = false;
4207
+ if (theme === "dark") {
4208
+ isDark = true;
4209
+ } else if (theme === "system") {
4210
+ isDark = mediaQuery.matches;
4211
+ }
4212
+ setResolvedTheme(isDark ? "dark" : "light");
4213
+ root.setAttribute("data-theme", isDark ? "dark" : "light");
4214
+ if (isDark) {
4215
+ root.classList.add("dark");
4216
+ } else {
4217
+ root.classList.remove("dark");
4218
+ }
4219
+ };
4220
+ updateTheme();
4221
+ mediaQuery.addEventListener("change", updateTheme);
4222
+ return () => mediaQuery.removeEventListener("change", updateTheme);
4223
+ }, [theme]);
4224
+ const t = (id, defaultText) => {
4225
+ if (messages[id]) {
4226
+ return messages[id];
4227
+ }
4228
+ return defaultText || id;
4229
+ };
4230
+ const value = {
4231
+ theme,
4232
+ resolvedTheme,
4233
+ setTheme: setThemeState,
4234
+ product,
4235
+ storageNamespace,
4236
+ i18n: { locale, t }
4237
+ };
4238
+ return /* @__PURE__ */ jsx53(UiContext.Provider, { value, children });
4239
+ };
4240
+ var useUi = () => useContext8(UiContext);
4241
+ var useTheme = () => {
4242
+ const { theme, resolvedTheme, setTheme } = useUi();
4243
+ return { theme, resolvedTheme, setTheme };
4244
+ };
4245
+ var useProduct = () => useUi().product;
4246
+ var useStorageNamespace = () => useUi().storageNamespace;
4247
+ var useI18n = () => useUi().i18n;
4248
+
4249
+ // src/testing/index.ts
4250
+ function createMockSlotContribution(overrides) {
4251
+ return {
4252
+ id: "test-slot-1",
4253
+ pack: "test-pack",
4254
+ slot: "dashboard.card",
4255
+ title: "Test Card",
4256
+ requiredScopes: ["general"],
4257
+ order: 10,
4258
+ ...overrides
4259
+ };
4260
+ }
4261
+ function createMockProfile(overrides) {
4262
+ return {
4263
+ id: "profile-1",
4264
+ displayName: "Primary User",
4265
+ role: "owner",
4266
+ scopes: ["general", "notes", "calendar"],
4267
+ ...overrides
4268
+ };
4269
+ }
4270
+ function createMockChatMessage(overrides) {
4271
+ return {
4272
+ id: "msg-1",
4273
+ role: "user",
4274
+ content: "Hello, world!",
4275
+ createdAt: "12:00 PM",
4276
+ ...overrides
4277
+ };
4278
+ }
4279
+
4280
+ // src/lib/storage-namespace.ts
4281
+ function getStorageKey(namespace, key, suffix) {
4282
+ const base = `${namespace}_${key}`;
4283
+ return suffix ? `${base}_${suffix}` : base;
4284
+ }
4285
+ function getScopedItem(namespace, key, suffix) {
4286
+ if (typeof window === "undefined") return null;
4287
+ try {
4288
+ return localStorage.getItem(getStorageKey(namespace, key, suffix));
4289
+ } catch {
4290
+ return null;
4291
+ }
4292
+ }
4293
+ function setScopedItem(namespace, key, value, suffix) {
4294
+ if (typeof window === "undefined") return;
4295
+ try {
4296
+ localStorage.setItem(getStorageKey(namespace, key, suffix), value);
4297
+ } catch {
4298
+ }
4299
+ }
4300
+ function removeScopedItem(namespace, key, suffix) {
4301
+ if (typeof window === "undefined") return;
4302
+ try {
4303
+ localStorage.removeItem(getStorageKey(namespace, key, suffix));
4304
+ } catch {
4305
+ }
4306
+ }
4307
+ export {
4308
+ ActivityLogDrawer,
4309
+ ActivityTimeline,
4310
+ AppLayout,
4311
+ AppRail,
4312
+ ApprovalCard,
4313
+ Avatar,
4314
+ AvatarFallback,
4315
+ AvatarImage,
4316
+ Badge,
4317
+ Button,
4318
+ Calendar,
4319
+ Card,
4320
+ CardContent,
4321
+ CardDescription,
4322
+ CardFooter,
4323
+ CardHeader,
4324
+ CardTitle,
4325
+ Chat,
4326
+ ChatAttachments,
4327
+ ChatComposer,
4328
+ ChatConnected,
4329
+ ChatMarkdown,
4330
+ ChatMessageItem,
4331
+ ChatRoot,
4332
+ ChatThread,
4333
+ Chip,
4334
+ CodeBlock,
4335
+ Dialog,
4336
+ DialogClose,
4337
+ DialogContent,
4338
+ DialogDescription,
4339
+ DialogFooter,
4340
+ DialogHeader,
4341
+ DialogTitle,
4342
+ DialogTrigger,
4343
+ EmptyState,
4344
+ ExecutionPlanCard,
4345
+ InlineError,
4346
+ MemberCard,
4347
+ Menu,
4348
+ MenuContent,
4349
+ MenuItem,
4350
+ MenuSeparator,
4351
+ MenuTrigger,
4352
+ MermaidDiagram,
4353
+ MessageToolbar,
4354
+ MobileTabBar,
4355
+ MobileTopBar,
4356
+ ModelSelector,
4357
+ NoteView,
4358
+ NotesList,
4359
+ NotificationCenter,
4360
+ Popover,
4361
+ PopoverContent,
4362
+ PopoverTrigger,
4363
+ ProfileEditModal,
4364
+ ProfileSwitcher,
4365
+ RecordSearch,
4366
+ Reminders,
4367
+ RoleMatrix,
4368
+ Routines,
4369
+ ScheduleAgenda,
4370
+ SegmentedControl,
4371
+ SettingsLayout,
4372
+ SettingsSectionSlotRenderer,
4373
+ ShareBundle,
4374
+ Sheet,
4375
+ SheetClose,
4376
+ SheetContent,
4377
+ SheetDescription,
4378
+ SheetFooter,
4379
+ SheetHeader,
4380
+ SheetTitle,
4381
+ SheetTrigger,
4382
+ Skeleton,
4383
+ SlotRenderer,
4384
+ Tabs,
4385
+ TabsContent,
4386
+ TabsList,
4387
+ TabsTrigger,
4388
+ TaskItem,
4389
+ TaskList,
4390
+ TeenHandoverBanner,
4391
+ ThinkingIndicator,
4392
+ ToastProvider,
4393
+ Toaster,
4394
+ ToolTraceCard,
4395
+ UiProvider,
4396
+ ViewerInvite,
4397
+ cn,
4398
+ createMockChatMessage,
4399
+ createMockProfile,
4400
+ createMockSlotContribution,
4401
+ definePackUi,
4402
+ filterSlotContributions,
4403
+ getScopedItem,
4404
+ getStorageKey,
4405
+ isScopeSatisfied,
4406
+ matchesScopePattern,
4407
+ removeScopedItem,
4408
+ setScopedItem,
4409
+ useChatContext,
4410
+ useI18n,
4411
+ useProduct,
4412
+ useStorageNamespace,
4413
+ useTheme,
4414
+ useToast,
4415
+ useUi,
4416
+ yarvellePreset
4417
+ };
4418
+ //# sourceMappingURL=index.js.map