@ai-matrx/design-system 0.60.1 → 0.60.6

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.
@@ -0,0 +1,3565 @@
1
+ "use client";
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/desktop/index.ts
32
+ var desktop_exports = {};
33
+ __export(desktop_exports, {
34
+ AppRail: () => AppRail,
35
+ AppRailAvatar: () => AppRailAvatar,
36
+ AppRailGroup: () => AppRailGroup,
37
+ AppRailItem: () => AppRailItem,
38
+ AppRailSpacer: () => AppRailSpacer,
39
+ Banner: () => Banner,
40
+ Button: () => Button,
41
+ CanvasLayout: () => CanvasLayout,
42
+ Checkbox: () => Checkbox,
43
+ CodeBlock: () => CodeBlock,
44
+ Collapsible: () => Collapsible,
45
+ CollapsibleContent: () => CollapsibleContent2,
46
+ CollapsibleTrigger: () => CollapsibleTrigger2,
47
+ ComingSoon: () => ComingSoon,
48
+ ConfirmDialog: () => ConfirmDialog,
49
+ ConfirmDialogHost: () => ConfirmDialogHost,
50
+ ContextMenu: () => ContextMenu,
51
+ ContextMenuContent: () => ContextMenuContent,
52
+ ContextMenuItem: () => ContextMenuItem,
53
+ ContextMenuSeparator: () => ContextMenuSeparator,
54
+ ContextMenuShortcut: () => ContextMenuShortcut,
55
+ ContextMenuTrigger: () => ContextMenuTrigger,
56
+ DataTable: () => DataTable,
57
+ Dialog: () => Dialog,
58
+ DialogClose: () => DialogClose,
59
+ DialogContent: () => DialogContent,
60
+ DialogDescription: () => DialogDescription,
61
+ DialogFooter: () => DialogFooter,
62
+ DialogHeader: () => DialogHeader,
63
+ DialogTitle: () => DialogTitle,
64
+ DialogTrigger: () => DialogTrigger,
65
+ DropdownMenu: () => DropdownMenu,
66
+ DropdownMenuCheckboxItem: () => DropdownMenuCheckboxItem,
67
+ DropdownMenuContent: () => DropdownMenuContent,
68
+ DropdownMenuGroup: () => DropdownMenuGroup,
69
+ DropdownMenuItem: () => DropdownMenuItem,
70
+ DropdownMenuLabel: () => DropdownMenuLabel,
71
+ DropdownMenuRadioGroup: () => DropdownMenuRadioGroup,
72
+ DropdownMenuRadioItem: () => DropdownMenuRadioItem,
73
+ DropdownMenuSeparator: () => DropdownMenuSeparator,
74
+ DropdownMenuShortcut: () => DropdownMenuShortcut,
75
+ DropdownMenuSub: () => DropdownMenuSub,
76
+ DropdownMenuSubContent: () => DropdownMenuSubContent,
77
+ DropdownMenuSubTrigger: () => DropdownMenuSubTrigger,
78
+ DropdownMenuTrigger: () => DropdownMenuTrigger,
79
+ ErrorBanner: () => ErrorBanner,
80
+ FIELD: () => FIELD,
81
+ FieldRow: () => FieldRow,
82
+ IconButton: () => IconButton,
83
+ Kbd: () => Kbd,
84
+ METER_THRESHOLDS: () => METER_THRESHOLDS,
85
+ Meter: () => Meter,
86
+ ModeSwitch: () => ModeSwitch,
87
+ OrganizationMark: () => OrganizationMark,
88
+ Page: () => Page,
89
+ PageHeader: () => PageHeader,
90
+ Popover: () => Popover,
91
+ PopoverAnchor: () => PopoverAnchor,
92
+ PopoverContent: () => PopoverContent,
93
+ PopoverTrigger: () => PopoverTrigger,
94
+ Resource: () => Resource,
95
+ Row: () => Row,
96
+ SearchField: () => SearchField,
97
+ Section: () => Section,
98
+ SectionContent: () => SectionContent,
99
+ Segmented: () => Segmented,
100
+ Select: () => Select,
101
+ Skeleton: () => Skeleton,
102
+ SourceList: () => SourceList,
103
+ SourceListItem: () => SourceListItem,
104
+ SourceListMore: () => SourceListMore,
105
+ SourceListSection: () => SourceListSection,
106
+ Spinner: () => Spinner,
107
+ StateView: () => StateView,
108
+ StatusDot: () => StatusDot,
109
+ StatusLight: () => StatusLight,
110
+ Switch: () => Switch,
111
+ TEXT_TONE: () => TEXT_TONE,
112
+ Tag: () => Tag,
113
+ Text: () => Text,
114
+ TextArea: () => TextArea,
115
+ TextField: () => TextField,
116
+ Toolbar: () => Toolbar,
117
+ ToolbarDivider: () => ToolbarDivider,
118
+ ToolbarSpacer: () => ToolbarSpacer,
119
+ Tooltip: () => Tooltip,
120
+ TooltipContent: () => TooltipContent,
121
+ TooltipProvider: () => TooltipProvider,
122
+ TooltipTrigger: () => TooltipTrigger,
123
+ buttonVariants: () => buttonVariants,
124
+ cn: () => cn,
125
+ errorMessage: () => errorMessage,
126
+ formatAge: () => formatAge,
127
+ formatBytes: () => formatBytes,
128
+ formatClockTime: () => formatClockTime,
129
+ formatDuration: () => formatDuration,
130
+ formatRelativeTime: () => formatRelativeTime,
131
+ formatUsage: () => formatUsage,
132
+ meterTone: () => meterTone,
133
+ organizationColor: () => organizationColor
134
+ });
135
+ module.exports = __toCommonJS(desktop_exports);
136
+
137
+ // src/desktop/cn.ts
138
+ var import_clsx = require("clsx");
139
+ var import_tailwind_merge = require("tailwind-merge");
140
+ var merge = (0, import_tailwind_merge.extendTailwindMerge)({
141
+ extend: {
142
+ theme: {
143
+ spacing: [
144
+ "control-sm",
145
+ "control",
146
+ "control-lg",
147
+ "row-compact",
148
+ "sidebar-row",
149
+ "row",
150
+ "row-tall",
151
+ "toolbar",
152
+ "icon-sm",
153
+ "icon",
154
+ "icon-lg",
155
+ "icon-xl"
156
+ ],
157
+ radius: ["control", "group", "panel"],
158
+ container: ["form", "page", "wide"],
159
+ text: ["title-large", "title-1", "title-2", "title-3", "headline", "body", "callout", "caption"],
160
+ shadow: ["control", "raised", "popover"]
161
+ }
162
+ }
163
+ });
164
+ function cn(...inputs) {
165
+ return merge((0, import_clsx.clsx)(inputs));
166
+ }
167
+
168
+ // src/desktop/text.tsx
169
+ var React = __toESM(require("react"), 1);
170
+ var import_jsx_runtime = require("react/jsx-runtime");
171
+ var VARIANT = {
172
+ "title-large": "text-title-large",
173
+ "title-1": "text-title-1",
174
+ "title-2": "text-title-2",
175
+ "title-3": "text-title-3",
176
+ headline: "text-headline",
177
+ body: "text-body",
178
+ callout: "text-callout",
179
+ caption: "text-caption"
180
+ };
181
+ var TEXT_TONE = {
182
+ primary: "text-label",
183
+ secondary: "text-label-secondary",
184
+ tertiary: "text-label-tertiary",
185
+ tint: "text-tint",
186
+ danger: "text-system-red",
187
+ warning: "text-system-orange",
188
+ success: "text-system-green"
189
+ };
190
+ var Text = React.forwardRef(function Text2({
191
+ variant = "body",
192
+ tone = "primary",
193
+ emphasized,
194
+ mono,
195
+ truncate,
196
+ tabular,
197
+ selectable,
198
+ as: Tag2 = "span",
199
+ className,
200
+ ...props
201
+ }, ref) {
202
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
203
+ Tag2,
204
+ {
205
+ ref,
206
+ "data-slot": "text",
207
+ className: cn(
208
+ VARIANT[variant],
209
+ TEXT_TONE[tone],
210
+ emphasized && "font-medium",
211
+ mono && "font-mono",
212
+ truncate && "min-w-0 truncate",
213
+ tabular && "tabular-nums",
214
+ selectable && "select-text",
215
+ className
216
+ ),
217
+ ...props
218
+ }
219
+ );
220
+ });
221
+
222
+ // src/desktop/spinner.tsx
223
+ var import_jsx_runtime2 = require("react/jsx-runtime");
224
+ var SPOKES = Array.from({ length: 12 }, (_, i) => i);
225
+ var SIZE = { sm: "size-icon-sm", md: "size-icon", lg: "size-icon-lg", xl: "size-icon-xl" };
226
+ function Spinner({ size = "md", label, className, ...props }) {
227
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
228
+ "svg",
229
+ {
230
+ viewBox: "0 0 24 24",
231
+ role: label ? "status" : void 0,
232
+ "aria-label": label,
233
+ "aria-hidden": label ? void 0 : true,
234
+ "data-slot": "spinner",
235
+ className: cn("mx-spinner shrink-0 text-label-secondary", SIZE[size], className),
236
+ ...props,
237
+ children: SPOKES.map((i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
238
+ "rect",
239
+ {
240
+ x: "11",
241
+ y: "2",
242
+ width: "2",
243
+ height: "6",
244
+ rx: "1",
245
+ fill: "currentColor",
246
+ opacity: 0.18 + 0.82 * (i + 1) / 12,
247
+ transform: `rotate(${i * 30} 12 12)`
248
+ },
249
+ i
250
+ ))
251
+ }
252
+ );
253
+ }
254
+
255
+ // src/desktop/button.tsx
256
+ var import_react_slot = require("@radix-ui/react-slot");
257
+ var import_class_variance_authority = require("class-variance-authority");
258
+ var React4 = __toESM(require("react"), 1);
259
+
260
+ // src/tooltip.tsx
261
+ var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
262
+ var React3 = __toESM(require("react"), 1);
263
+
264
+ // src/cn.ts
265
+ var import_clsx2 = require("clsx");
266
+ var import_tailwind_merge2 = require("tailwind-merge");
267
+ function cn2(...inputs) {
268
+ return (0, import_tailwind_merge2.twMerge)((0, import_clsx2.clsx)(inputs));
269
+ }
270
+
271
+ // src/motion.ts
272
+ var MOTION_OVERLAY = "matrx-motion-overlay";
273
+ var MOTION_DIALOG = "matrx-motion-dialog";
274
+ var CENTERED_DIALOG = "matrx-dialog-centered";
275
+ var POPPER_OFFSET = "matrx-popper-offset";
276
+ var MOTION_BOTTOM_SHEET = "matrx-motion-bottom-sheet";
277
+ var MOTION_POPPER = "matrx-motion-popper";
278
+ var MOTION_SHEET = {
279
+ top: "matrx-motion-sheet-top",
280
+ bottom: "matrx-motion-sheet-bottom",
281
+ left: "matrx-motion-sheet-left",
282
+ right: "matrx-motion-sheet-right",
283
+ center: "matrx-motion-sheet-center"
284
+ };
285
+ var MOTION_PULSE = "matrx-pulse";
286
+ var MOTION_SPIN = "matrx-spin";
287
+ var ALL_MOTION_CLASSES = [
288
+ MOTION_OVERLAY,
289
+ MOTION_DIALOG,
290
+ MOTION_BOTTOM_SHEET,
291
+ MOTION_POPPER,
292
+ ...Object.values(MOTION_SHEET),
293
+ MOTION_PULSE,
294
+ MOTION_SPIN
295
+ ];
296
+
297
+ // src/portal-container.tsx
298
+ var React2 = __toESM(require("react"), 1);
299
+ var import_jsx_runtime3 = require("react/jsx-runtime");
300
+ var CONTEXT_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.portal-container-context");
301
+ var contextRegistry = globalThis;
302
+ var PortalContainerContext = contextRegistry[CONTEXT_SLOT] ??= React2.createContext(void 0);
303
+ function PortalContainerProvider({
304
+ container,
305
+ children
306
+ }) {
307
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PortalContainerContext.Provider, { value: container ?? void 0, children });
308
+ }
309
+ function usePortalContainer(explicit) {
310
+ const injected = React2.useContext(PortalContainerContext);
311
+ if (explicit !== void 0) {
312
+ return explicit ?? void 0;
313
+ }
314
+ return injected ?? void 0;
315
+ }
316
+
317
+ // src/title-tooltips.ts
318
+ var TITLE_TOOLTIP_ATTR = "data-matrx-title";
319
+ var TOOLTIP_TRIGGER_ATTR = "data-matrx-tooltip-trigger";
320
+ var NATIVE_TITLE_OPT_OUT_ATTR = "data-native-title";
321
+ var OPEN_DELAY_MS = 350;
322
+ var SKIP_DELAY_MS = 500;
323
+ var GAP_PX = 6;
324
+ var EDGE_PX = 8;
325
+ var SURFACE_CLASS = "matrx-tooltip matrx-title-tooltip matrx-motion-popper z-[10001] rounded-md border border-border bg-popover px-2.5 py-1 text-xs font-medium text-popover-foreground";
326
+ var INSTALLATION_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/design-system/title-tooltips");
327
+ var installations = {
328
+ get: (doc) => doc[INSTALLATION_KEY],
329
+ set: (doc, value) => {
330
+ doc[INSTALLATION_KEY] = value;
331
+ },
332
+ delete: (doc) => {
333
+ delete doc[INSTALLATION_KEY];
334
+ }
335
+ };
336
+ function acquireTitleTooltips(doc = typeof document === "undefined" ? void 0 : document) {
337
+ if (!doc) return () => {
338
+ };
339
+ const existing = installations.get(doc);
340
+ if (existing) {
341
+ existing.count += 1;
342
+ } else {
343
+ installations.set(doc, { count: 1, uninstall: install(doc) });
344
+ }
345
+ let released = false;
346
+ return () => {
347
+ if (released) return;
348
+ released = true;
349
+ const current = installations.get(doc);
350
+ if (!current) return;
351
+ current.count -= 1;
352
+ if (current.count <= 0) {
353
+ current.uninstall();
354
+ installations.delete(doc);
355
+ }
356
+ };
357
+ }
358
+ function install(doc) {
359
+ const win = doc.defaultView;
360
+ let active = null;
361
+ let surface = null;
362
+ let openTimer;
363
+ let lastClosedAt = 0;
364
+ const HTMLElementCtor = win?.HTMLElement;
365
+ const titledAncestor = (node) => {
366
+ if (!HTMLElementCtor || !(node instanceof win.Node)) return null;
367
+ const start = node instanceof HTMLElementCtor ? node : node.parentElement;
368
+ if (!start) return null;
369
+ const el = start.closest(`[title], [${TITLE_TOOLTIP_ATTR}]`);
370
+ if (!el || !(el instanceof HTMLElementCtor)) return null;
371
+ if (el.closest(`[${NATIVE_TITLE_OPT_OUT_ATTR}]`)) return null;
372
+ return el;
373
+ };
374
+ const textOf = (el) => (el.getAttribute(TITLE_TOOLTIP_ATTR) ?? el.getAttribute("title") ?? "").trim();
375
+ const lift = (el) => {
376
+ const title = el.getAttribute("title");
377
+ if (title === null) return;
378
+ el.setAttribute(TITLE_TOOLTIP_ATTR, title);
379
+ el.removeAttribute("title");
380
+ };
381
+ const restore = (el) => {
382
+ const held = el.getAttribute(TITLE_TOOLTIP_ATTR);
383
+ if (held === null) return;
384
+ if (!el.hasAttribute("title")) el.setAttribute("title", held);
385
+ el.removeAttribute(TITLE_TOOLTIP_ATTR);
386
+ };
387
+ const ensureSurface = () => {
388
+ if (surface && surface.isConnected) return surface;
389
+ surface = doc.createElement("div");
390
+ surface.setAttribute("role", "tooltip");
391
+ surface.setAttribute("data-slot", "title-tooltip");
392
+ surface.className = SURFACE_CLASS;
393
+ surface.style.visibility = "hidden";
394
+ doc.body.appendChild(surface);
395
+ return surface;
396
+ };
397
+ const preferredSide = (el) => {
398
+ const hint = el.closest("[data-title-side]")?.getAttribute("data-title-side");
399
+ return hint === "bottom" || hint === "left" || hint === "right" ? hint : "top";
400
+ };
401
+ const place = (el, node) => {
402
+ const vw = win?.innerWidth ?? 0;
403
+ const vh = win?.innerHeight ?? 0;
404
+ const anchor = el.getBoundingClientRect();
405
+ const box = node.getBoundingClientRect();
406
+ const fits = {
407
+ top: anchor.top - GAP_PX - box.height >= EDGE_PX,
408
+ bottom: anchor.bottom + GAP_PX + box.height <= vh - EDGE_PX,
409
+ left: anchor.left - GAP_PX - box.width >= EDGE_PX,
410
+ right: anchor.right + GAP_PX + box.width <= vw - EDGE_PX
411
+ };
412
+ const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };
413
+ const wanted = preferredSide(el);
414
+ const side = fits[wanted] ? wanted : fits[opposite[wanted]] ? opposite[wanted] : wanted;
415
+ let x;
416
+ let y;
417
+ if (side === "top" || side === "bottom") {
418
+ x = anchor.left + anchor.width / 2 - box.width / 2;
419
+ y = side === "top" ? anchor.top - GAP_PX - box.height : anchor.bottom + GAP_PX;
420
+ } else {
421
+ y = anchor.top + anchor.height / 2 - box.height / 2;
422
+ x = side === "left" ? anchor.left - GAP_PX - box.width : anchor.right + GAP_PX;
423
+ }
424
+ x = Math.min(Math.max(x, EDGE_PX), Math.max(EDGE_PX, vw - EDGE_PX - box.width));
425
+ y = Math.min(Math.max(y, EDGE_PX), Math.max(EDGE_PX, vh - EDGE_PX - box.height));
426
+ node.style.transform = `translate(${Math.round(x)}px, ${Math.round(y)}px)`;
427
+ node.setAttribute("data-side", side);
428
+ };
429
+ const isShown = (node, root) => {
430
+ const rect = node.getBoundingClientRect();
431
+ if (rect.width <= 0 || rect.height <= 0) return false;
432
+ for (let cur = node; cur; cur = cur === root ? null : cur.parentElement) {
433
+ const cs = win?.getComputedStyle(cur);
434
+ if (!cs) return false;
435
+ if (cs.display === "none" || cs.visibility === "hidden" || Number(cs.opacity) === 0) return false;
436
+ }
437
+ return true;
438
+ };
439
+ const repeatsVisibleText = (el, text) => {
440
+ const norm = (t) => t.replace(/\s+/g, " ").trim().toLowerCase();
441
+ const want = norm(text);
442
+ if (!want || !win) return false;
443
+ const walker = doc.createTreeWalker(el, win.NodeFilter.SHOW_TEXT);
444
+ for (let node = walker.nextNode(); node; node = walker.nextNode()) {
445
+ if (norm(node.textContent ?? "") !== want) continue;
446
+ const host = node.parentElement;
447
+ if (!host || !isShown(host, el)) continue;
448
+ if (host.scrollWidth > host.clientWidth + 1) continue;
449
+ return true;
450
+ }
451
+ return false;
452
+ };
453
+ const show = (el, instant) => {
454
+ if (active !== el) return;
455
+ if (el.closest(`[${TOOLTIP_TRIGGER_ATTR}]`)) return;
456
+ const text = textOf(el);
457
+ if (!text || !el.isConnected) return;
458
+ if (repeatsVisibleText(el, text)) return;
459
+ const node = ensureSurface();
460
+ node.textContent = text;
461
+ node.style.visibility = "hidden";
462
+ node.setAttribute("data-state", instant ? "instant-open" : "delayed-open");
463
+ place(el, node);
464
+ node.style.visibility = "visible";
465
+ if (el.id) node.id = `${el.id}-title-tooltip`;
466
+ };
467
+ const hide = () => {
468
+ if (openTimer !== void 0) clearTimeout(openTimer);
469
+ openTimer = void 0;
470
+ if (surface && surface.style.visibility === "visible") lastClosedAt = Date.now();
471
+ if (surface) {
472
+ surface.style.visibility = "hidden";
473
+ surface.removeAttribute("data-state");
474
+ }
475
+ };
476
+ const activate = (el) => {
477
+ if (active === el) return;
478
+ deactivate();
479
+ active = el;
480
+ lift(el);
481
+ const instant = Date.now() - lastClosedAt < SKIP_DELAY_MS;
482
+ if (instant) show(el, true);
483
+ else openTimer = setTimeout(() => show(el, false), OPEN_DELAY_MS);
484
+ };
485
+ const deactivate = () => {
486
+ hide();
487
+ if (active) restore(active);
488
+ active = null;
489
+ };
490
+ const onPointerOver = (e) => {
491
+ if (e.pointerType === "touch") return;
492
+ const el = titledAncestor(e.target);
493
+ if (el) activate(el);
494
+ else if (active) deactivate();
495
+ };
496
+ const onPointerOut = (e) => {
497
+ if (!active) return;
498
+ const next = e.relatedTarget;
499
+ if (next instanceof win.Node && active.contains(next)) return;
500
+ deactivate();
501
+ };
502
+ const onFocusIn = (e) => {
503
+ const el = titledAncestor(e.target);
504
+ if (!el) return;
505
+ let visible = true;
506
+ try {
507
+ visible = e.target.matches(":focus-visible");
508
+ } catch {
509
+ visible = true;
510
+ }
511
+ if (visible) activate(el);
512
+ };
513
+ const onFocusOut = (e) => {
514
+ if (!active) return;
515
+ const next = e.relatedTarget;
516
+ if (next instanceof win.Node && active.contains(next)) return;
517
+ deactivate();
518
+ };
519
+ const onDismiss = () => deactivate();
520
+ const onKeyDown = (e) => {
521
+ if (e.key === "Escape") deactivate();
522
+ };
523
+ doc.addEventListener("pointerover", onPointerOver, true);
524
+ doc.addEventListener("pointerout", onPointerOut, true);
525
+ doc.addEventListener("focusin", onFocusIn, true);
526
+ doc.addEventListener("focusout", onFocusOut, true);
527
+ doc.addEventListener("pointerdown", onDismiss, true);
528
+ doc.addEventListener("keydown", onKeyDown, true);
529
+ doc.addEventListener("scroll", onDismiss, true);
530
+ win?.addEventListener("blur", onDismiss);
531
+ return () => {
532
+ deactivate();
533
+ doc.removeEventListener("pointerover", onPointerOver, true);
534
+ doc.removeEventListener("pointerout", onPointerOut, true);
535
+ doc.removeEventListener("focusin", onFocusIn, true);
536
+ doc.removeEventListener("focusout", onFocusOut, true);
537
+ doc.removeEventListener("pointerdown", onDismiss, true);
538
+ doc.removeEventListener("keydown", onKeyDown, true);
539
+ doc.removeEventListener("scroll", onDismiss, true);
540
+ win?.removeEventListener("blur", onDismiss);
541
+ surface?.remove();
542
+ surface = null;
543
+ };
544
+ }
545
+
546
+ // src/tooltip.tsx
547
+ var import_jsx_runtime4 = require("react/jsx-runtime");
548
+ function TooltipProvider({ titleTooltips = true, ...props }) {
549
+ React3.useEffect(() => {
550
+ if (!titleTooltips) return;
551
+ return acquireTitleTooltips();
552
+ }, [titleTooltips]);
553
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TooltipPrimitive.Provider, { ...props });
554
+ }
555
+ var Tooltip = TooltipPrimitive.Root;
556
+ var TooltipTrigger = React3.forwardRef((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TooltipPrimitive.Trigger, { ref, ...{ [TOOLTIP_TRIGGER_ATTR]: "" }, ...props }));
557
+ TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName;
558
+ var TooltipContent = React3.forwardRef(({ className, sideOffset = 4, container, animated = true, ...props }, ref) => {
559
+ const resolved = usePortalContainer(container);
560
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TooltipPrimitive.Portal, { container: resolved ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
561
+ TooltipPrimitive.Content,
562
+ {
563
+ ref,
564
+ "data-slot": "tooltip-content",
565
+ sideOffset,
566
+ className: cn2(
567
+ "matrx-tooltip z-[10001] overflow-hidden rounded-md border border-border bg-popover px-2.5 py-1 text-xs font-medium text-popover-foreground",
568
+ animated && MOTION_POPPER,
569
+ className
570
+ ),
571
+ ...props
572
+ }
573
+ ) });
574
+ });
575
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
576
+
577
+ // src/desktop/button.tsx
578
+ var import_jsx_runtime5 = require("react/jsx-runtime");
579
+ var buttonVariants = (0, import_class_variance_authority.cva)(
580
+ "focus-ring inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-control font-medium transition-colors duration-100 disabled:pointer-events-none disabled:opacity-40 [&_svg]:pointer-events-none [&_svg]:shrink-0",
581
+ {
582
+ variants: {
583
+ variant: {
584
+ primary: "bg-tint text-tint-label shadow-control hover:brightness-110 active:brightness-95 disabled:bg-fill-secondary disabled:text-label-tertiary disabled:opacity-100 disabled:shadow-none",
585
+ secondary: "bg-control text-label shadow-control hover:bg-fill-secondary active:bg-fill-tertiary",
586
+ plain: "bg-transparent text-label hover:bg-fill-secondary active:bg-fill-tertiary",
587
+ destructive: "bg-control text-system-red shadow-control hover:bg-fill-secondary active:bg-fill-tertiary"
588
+ },
589
+ size: {
590
+ sm: "h-control-sm px-2 text-callout [&_svg]:size-icon-sm",
591
+ md: "h-control px-3 text-body [&_svg]:size-icon",
592
+ lg: "h-control-lg px-4 text-body [&_svg]:size-icon"
593
+ }
594
+ },
595
+ defaultVariants: { variant: "secondary", size: "md" }
596
+ }
597
+ );
598
+ var Button = React4.forwardRef(function Button2({ variant, size, icon, busy, asChild, disabled, className, children, type = "button", ...props }, ref) {
599
+ const Comp = asChild ? import_react_slot.Slot : "button";
600
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
601
+ Comp,
602
+ {
603
+ ref,
604
+ type: asChild ? void 0 : type,
605
+ "data-slot": "button",
606
+ disabled: disabled || busy,
607
+ "aria-busy": busy || void 0,
608
+ className: cn(buttonVariants({ variant, size }), className),
609
+ ...props,
610
+ children: asChild ? children : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
611
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Spinner, { size: size === "sm" ? "sm" : "md" }) : icon,
612
+ children
613
+ ] })
614
+ }
615
+ );
616
+ });
617
+ var iconButtonVariants = (0, import_class_variance_authority.cva)(
618
+ "focus-ring inline-flex shrink-0 select-none items-center justify-center rounded-control text-label-secondary transition-colors duration-100 hover:bg-fill-secondary hover:text-label active:bg-fill-tertiary disabled:pointer-events-none disabled:opacity-40 data-[active=true]:bg-fill-secondary data-[active=true]:text-label [&_svg]:pointer-events-none [&_svg]:shrink-0",
619
+ {
620
+ variants: {
621
+ size: {
622
+ sm: "size-control-sm [&_svg]:size-icon-sm",
623
+ md: "size-control [&_svg]:size-icon"
624
+ }
625
+ },
626
+ defaultVariants: { size: "md" }
627
+ }
628
+ );
629
+ var IconButton = React4.forwardRef(function IconButton2({ icon, label, shortcut, active, size, className, type = "button", ...props }, ref) {
630
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Tooltip, { children: [
631
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
632
+ "button",
633
+ {
634
+ ref,
635
+ type,
636
+ "data-slot": "icon-button",
637
+ "aria-label": label,
638
+ "aria-pressed": active === void 0 ? void 0 : active,
639
+ "data-active": active || void 0,
640
+ className: cn(iconButtonVariants({ size }), className),
641
+ ...props,
642
+ children: icon
643
+ }
644
+ ) }),
645
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(TooltipContent, { children: [
646
+ label,
647
+ shortcut ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ml-2 opacity-60", children: shortcut }) : null
648
+ ] })
649
+ ] });
650
+ });
651
+
652
+ // src/desktop/field.tsx
653
+ var React5 = __toESM(require("react"), 1);
654
+
655
+ // src/icons.tsx
656
+ var import_jsx_runtime6 = require("react/jsx-runtime");
657
+ function lucideProps(props) {
658
+ return {
659
+ xmlns: "http://www.w3.org/2000/svg",
660
+ viewBox: "0 0 24 24",
661
+ fill: "none",
662
+ stroke: "currentColor",
663
+ strokeWidth: 2,
664
+ strokeLinecap: "round",
665
+ strokeLinejoin: "round",
666
+ "aria-hidden": true,
667
+ ...props
668
+ };
669
+ }
670
+ function Loader2Icon(props) {
671
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
672
+ }
673
+ function ChevronRightIcon(props) {
674
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m9 18 6-6-6-6" }) });
675
+ }
676
+ function ChevronDownIcon(props) {
677
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 9 6 6 6-6" }) });
678
+ }
679
+ function MoreHorizontalIcon(props) {
680
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { ...lucideProps(props), children: [
681
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
682
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "19", cy: "12", r: "1" }),
683
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "5", cy: "12", r: "1" })
684
+ ] });
685
+ }
686
+ function ChevronsUpDownIcon(props) {
687
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { ...lucideProps(props), children: [
688
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m7 15 5 5 5-5" }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m7 9 5-5 5 5" })
690
+ ] });
691
+ }
692
+ function XIcon(props) {
693
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { ...lucideProps(props), children: [
694
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M18 6 6 18" }),
695
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 6 12 12" })
696
+ ] });
697
+ }
698
+ function radixProps(props) {
699
+ return {
700
+ xmlns: "http://www.w3.org/2000/svg",
701
+ viewBox: "0 0 15 15",
702
+ width: 15,
703
+ height: 15,
704
+ fill: "none",
705
+ "aria-hidden": true,
706
+ ...props
707
+ };
708
+ }
709
+ function MagnifyingGlassIcon(props) {
710
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
711
+ "path",
712
+ {
713
+ d: "M10 6.5C10 8.433 8.433 10 6.5 10C4.567 10 3 8.433 3 6.5C3 4.567 4.567 3 6.5 3C8.433 3 10 4.567 10 6.5ZM9.30884 10.0159C8.53901 10.6318 7.56251 11 6.5 11C4.01472 11 2 8.98528 2 6.5C2 4.01472 4.01472 2 6.5 2C8.98528 2 11 4.01472 11 6.5C11 7.56251 10.6318 8.53901 10.0159 9.30884L12.8536 12.1464C13.0488 12.3417 13.0488 12.6583 12.8536 12.8536C12.6583 13.0488 12.3417 13.0488 12.1464 12.8536L9.30884 10.0159Z",
714
+ fill: "currentColor",
715
+ fillRule: "evenodd",
716
+ clipRule: "evenodd"
717
+ }
718
+ ) });
719
+ }
720
+ function CheckIcon(props) {
721
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
722
+ "path",
723
+ {
724
+ d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z",
725
+ fill: "currentColor",
726
+ fillRule: "evenodd",
727
+ clipRule: "evenodd"
728
+ }
729
+ ) });
730
+ }
731
+ function DividerHorizontalIcon(props) {
732
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
733
+ "path",
734
+ {
735
+ d: "M2 7.5C2 7.22386 2.22386 7 2.5 7H12.5C12.7761 7 13 7.22386 13 7.5C13 7.77614 12.7761 8 12.5 8H2.5C2.22386 8 2 7.77614 2 7.5Z",
736
+ fill: "currentColor",
737
+ fillRule: "evenodd",
738
+ clipRule: "evenodd"
739
+ }
740
+ ) });
741
+ }
742
+ function DotFilledIcon(props) {
743
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
744
+ "path",
745
+ {
746
+ d: "M9.875 7.5C9.875 8.81168 8.81168 9.875 7.5 9.875C6.18832 9.875 5.125 8.81168 5.125 7.5C5.125 6.18832 6.18832 5.125 7.5 5.125C8.81168 5.125 9.875 6.18832 9.875 7.5Z",
747
+ fill: "currentColor"
748
+ }
749
+ ) });
750
+ }
751
+ function RadixChevronRightIcon(props) {
752
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
753
+ "path",
754
+ {
755
+ d: "M6.1584 3.13508C6.35985 2.94621 6.67627 2.95642 6.86514 3.15788L10.6151 7.15788C10.7954 7.3502 10.7954 7.64949 10.6151 7.84182L6.86514 11.8418C6.67627 12.0433 6.35985 12.0535 6.1584 11.8646C5.95694 11.6757 5.94673 11.3593 6.1356 11.1579L9.565 7.49985L6.1356 3.84182C5.94673 3.64036 5.95694 3.32394 6.1584 3.13508Z",
756
+ fill: "currentColor",
757
+ fillRule: "evenodd",
758
+ clipRule: "evenodd"
759
+ }
760
+ ) });
761
+ }
762
+ function RadixChevronDownIcon(props) {
763
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
764
+ "path",
765
+ {
766
+ d: "M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z",
767
+ fill: "currentColor",
768
+ fillRule: "evenodd",
769
+ clipRule: "evenodd"
770
+ }
771
+ ) });
772
+ }
773
+ function RadixChevronUpIcon(props) {
774
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
775
+ "path",
776
+ {
777
+ d: "M3.13523 8.84197C3.3241 9.04343 3.64052 9.05363 3.84197 8.86477L7.5 5.43536L11.158 8.86477C11.3595 9.05363 11.6759 9.04343 11.8648 8.84197C12.0536 8.64051 12.0434 8.32409 11.842 8.13523L7.84197 4.38523C7.64964 4.20492 7.35036 4.20492 7.15803 4.38523L3.15803 8.13523C2.95657 8.32409 2.94637 8.64051 3.13523 8.84197Z",
778
+ fill: "currentColor",
779
+ fillRule: "evenodd",
780
+ clipRule: "evenodd"
781
+ }
782
+ ) });
783
+ }
784
+ function DragHandleDots2Icon(props) {
785
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
786
+ "path",
787
+ {
788
+ d: "M4.5 2.5C5.05228 2.5 5.5 2.05228 5.5 1.5C5.5 0.947715 5.05228 0.5 4.5 0.5C3.94772 0.5 3.5 0.947715 3.5 1.5C3.5 2.05228 3.94772 2.5 4.5 2.5ZM4.5 6.5C5.05228 6.5 5.5 6.05229 5.5 5.5C5.5 4.94771 5.05228 4.5 4.5 4.5C3.94772 4.5 3.5 4.94771 3.5 5.5C3.5 6.05229 3.94772 6.5 4.5 6.5ZM5.5 9.5C5.5 10.0523 5.05228 10.5 4.5 10.5C3.94772 10.5 3.5 10.0523 3.5 9.5C3.5 8.94771 3.94772 8.5 4.5 8.5C5.05228 8.5 5.5 8.94771 5.5 9.5ZM4.5 14.5C5.05228 14.5 5.5 14.0523 5.5 13.5C5.5 12.9477 5.05228 12.5 4.5 12.5C3.94772 12.5 3.5 12.9477 3.5 13.5C3.5 14.0523 3.94772 14.5 4.5 14.5ZM11.5 1.5C11.5 2.05228 11.0523 2.5 10.5 2.5C9.94771 2.5 9.5 2.05228 9.5 1.5C9.5 0.947715 9.94771 0.5 10.5 0.5C11.0523 0.5 11.5 0.947715 11.5 1.5ZM10.5 6.5C11.0523 6.5 11.5 6.05229 11.5 5.5C11.5 4.94771 11.0523 4.5 10.5 4.5C9.94771 4.5 9.5 4.94771 9.5 5.5C9.5 6.05229 9.94771 6.5 10.5 6.5ZM11.5 9.5C11.5 10.0523 11.0523 10.5 10.5 10.5C9.94771 10.5 9.5 10.0523 9.5 9.5C9.5 8.94771 9.94771 8.5 10.5 8.5C11.0523 8.5 11.5 8.94771 11.5 9.5ZM10.5 14.5C11.0523 14.5 11.5 14.0523 11.5 13.5C11.5 12.9477 11.0523 12.5 10.5 12.5C9.94771 12.5 9.5 12.9477 9.5 13.5C9.5 14.0523 9.94771 14.5 10.5 14.5Z",
789
+ fill: "currentColor",
790
+ fillRule: "evenodd",
791
+ clipRule: "evenodd"
792
+ }
793
+ ) });
794
+ }
795
+
796
+ // src/desktop/field.tsx
797
+ var import_jsx_runtime7 = require("react/jsx-runtime");
798
+ var FIELD = "focus-ring w-full min-w-0 rounded-control bg-control text-body text-label shadow-control placeholder:text-label-tertiary disabled:opacity-40 read-only:bg-fill";
799
+ var TextField = React5.forwardRef(function TextField2({ size = "md", invalid, className, ...props }, ref) {
800
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
801
+ "input",
802
+ {
803
+ ref,
804
+ "data-slot": "text-field",
805
+ "aria-invalid": invalid || void 0,
806
+ className: cn(
807
+ FIELD,
808
+ "select-text px-2",
809
+ size === "sm" ? "h-control-sm text-callout" : "h-control",
810
+ invalid && "outline outline-2 outline-system-red/60",
811
+ className
812
+ ),
813
+ ...props
814
+ }
815
+ );
816
+ });
817
+ var TextArea = React5.forwardRef(function TextArea2({ invalid, className, rows = 4, ...props }, ref) {
818
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
819
+ "textarea",
820
+ {
821
+ ref,
822
+ rows,
823
+ "data-slot": "text-area",
824
+ "aria-invalid": invalid || void 0,
825
+ className: cn(FIELD, "select-text resize-none px-2 py-1.5", invalid && "outline outline-2 outline-system-red/60", className),
826
+ ...props
827
+ }
828
+ );
829
+ });
830
+ var SearchField = React5.forwardRef(function SearchField2({ value, onValueChange, size = "md", placeholder = "Search", className, onKeyDown, ...props }, ref) {
831
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
832
+ "div",
833
+ {
834
+ "data-slot": "search-field",
835
+ className: cn("relative flex items-center", size === "sm" ? "h-control-sm" : "h-control", className),
836
+ children: [
837
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MagnifyingGlassIcon, { className: "pointer-events-none absolute left-2 size-icon-sm text-label-tertiary" }),
838
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
839
+ "input",
840
+ {
841
+ ref,
842
+ type: "search",
843
+ value,
844
+ placeholder,
845
+ onChange: (event) => onValueChange(event.target.value),
846
+ onKeyDown: (event) => {
847
+ if (event.key === "Escape" && value) {
848
+ event.preventDefault();
849
+ onValueChange("");
850
+ }
851
+ onKeyDown?.(event);
852
+ },
853
+ className: cn(
854
+ FIELD,
855
+ "h-full select-text bg-fill pl-7 pr-7 shadow-none [&::-webkit-search-cancel-button]:hidden",
856
+ size === "sm" && "text-callout"
857
+ ),
858
+ ...props
859
+ }
860
+ ),
861
+ value ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
862
+ "button",
863
+ {
864
+ type: "button",
865
+ "aria-label": "Clear search",
866
+ onClick: () => onValueChange(""),
867
+ className: "focus-ring absolute right-1.5 flex size-icon items-center justify-center rounded-full bg-label-tertiary text-content hover:bg-label-secondary",
868
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(XIcon, { className: "size-2.5", strokeWidth: 3 })
869
+ }
870
+ ) : null
871
+ ]
872
+ }
873
+ );
874
+ });
875
+
876
+ // src/desktop/select.tsx
877
+ var SelectPrimitive2 = __toESM(require("@radix-ui/react-select"), 1);
878
+
879
+ // src/select.tsx
880
+ var SelectPrimitive = __toESM(require("@radix-ui/react-select"), 1);
881
+ var import_class_variance_authority2 = require("class-variance-authority");
882
+ var React6 = __toESM(require("react"), 1);
883
+
884
+ // src/field-surface.ts
885
+ var FIELD_SURFACE_CLASS = "border border-border bg-card";
886
+
887
+ // src/select.tsx
888
+ var import_jsx_runtime8 = require("react/jsx-runtime");
889
+ var selectTriggerVariants = (0, import_class_variance_authority2.cva)(
890
+ `flex w-full items-center justify-between gap-2 whitespace-nowrap rounded-md ${FIELD_SURFACE_CLASS} text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground transition-colors hover:bg-accent hover:border-accent-foreground/20 focus:outline-none focus:ring-1 focus:ring-primary/30 focus:border-primary/40 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:min-w-0 [&>span]:line-clamp-1`,
891
+ {
892
+ variants: {
893
+ size: {
894
+ sm: "h-7 px-2 py-1 text-xs",
895
+ default: "h-9 px-3 py-1",
896
+ lg: "h-10 px-3 py-2"
897
+ }
898
+ },
899
+ defaultVariants: {
900
+ size: "default"
901
+ }
902
+ }
903
+ );
904
+ function SelectChevron({ className, size = "default" }) {
905
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
906
+ RadixChevronDownIcon,
907
+ {
908
+ "aria-hidden": "true",
909
+ "data-select-chevron": "",
910
+ className: cn2(size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4", "shrink-0 opacity-50", className)
911
+ }
912
+ );
913
+ }
914
+ var SelectTrigger = React6.forwardRef(({ className, children, hideArrow = false, size, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
915
+ SelectPrimitive.Trigger,
916
+ {
917
+ ref,
918
+ className: cn2(selectTriggerVariants({ size, className })),
919
+ ...props,
920
+ children: [
921
+ children,
922
+ !hideArrow && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectChevron, { size: size === "sm" ? "sm" : "default" }) })
923
+ ]
924
+ }
925
+ ));
926
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
927
+ var SelectScrollUpButton = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
928
+ SelectPrimitive.ScrollUpButton,
929
+ {
930
+ ref,
931
+ className: cn2(
932
+ "flex cursor-default items-center justify-center py-1",
933
+ className
934
+ ),
935
+ ...props,
936
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RadixChevronUpIcon, {})
937
+ }
938
+ ));
939
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
940
+ var SelectScrollDownButton = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
941
+ SelectPrimitive.ScrollDownButton,
942
+ {
943
+ ref,
944
+ className: cn2(
945
+ "flex cursor-default items-center justify-center py-1",
946
+ className
947
+ ),
948
+ ...props,
949
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RadixChevronDownIcon, {})
950
+ }
951
+ ));
952
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
953
+ var SelectContent = React6.forwardRef(
954
+ ({
955
+ className,
956
+ children,
957
+ position = "popper",
958
+ container,
959
+ animated = true,
960
+ ...props
961
+ }, ref) => {
962
+ const portalContainer = usePortalContainer(container);
963
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
964
+ SelectPrimitive.Content,
965
+ {
966
+ ref,
967
+ className: cn2(
968
+ "relative z-[10001] max-h-96 min-w-[8rem] max-w-[calc(100vw-2rem)] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md",
969
+ animated && MOTION_POPPER,
970
+ // The resting gap from the trigger. It is the `translate` property
971
+ // (POPPER_OFFSET), never Tailwind translate utilities: those compose
972
+ // with `transform` on a v4 host and are REPLACED by it on a v3 one,
973
+ // so on v3 the animation ate the gap and the surface snapped 4px at
974
+ // the end. Same law as the centred dialog card — see motion.ts.
975
+ position === "popper" && POPPER_OFFSET,
976
+ className
977
+ ),
978
+ position,
979
+ ...props,
980
+ children: [
981
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectScrollUpButton, {}),
982
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
983
+ SelectPrimitive.Viewport,
984
+ {
985
+ className: cn2(
986
+ "max-w-full overflow-y-auto p-0.5",
987
+ position === "popper" && "w-full min-w-[var(--radix-select-trigger-width)] max-h-[var(--radix-select-content-available-height)]"
988
+ ),
989
+ children
990
+ }
991
+ ),
992
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectScrollDownButton, {})
993
+ ]
994
+ }
995
+ ) });
996
+ }
997
+ );
998
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
999
+ var SelectLabel = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1000
+ SelectPrimitive.Label,
1001
+ {
1002
+ ref,
1003
+ className: cn2("px-2 py-1.5 text-sm font-semibold", className),
1004
+ ...props
1005
+ }
1006
+ ));
1007
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
1008
+ var SelectItem = React6.forwardRef(({ className, children, description, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1009
+ SelectPrimitive.Item,
1010
+ {
1011
+ ref,
1012
+ className: cn2(
1013
+ "relative flex w-full min-w-0 select-none rounded-sm py-1 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:opacity-50",
1014
+ description ? "flex-col items-start gap-0.5 py-1.5" : "items-center",
1015
+ className
1016
+ ),
1017
+ ...props,
1018
+ children: [
1019
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon, { className: "h-4 w-4" }) }) }),
1020
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "min-w-0 whitespace-normal break-words [overflow-wrap:anywhere]", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.ItemText, { children }) }),
1021
+ description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "block min-w-0 break-words text-xs leading-snug text-muted-foreground [overflow-wrap:anywhere]", children: description }) : null
1022
+ ]
1023
+ }
1024
+ ));
1025
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
1026
+ var SelectSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1027
+ SelectPrimitive.Separator,
1028
+ {
1029
+ ref,
1030
+ className: cn2("-mx-1 my-1 h-px bg-muted", className),
1031
+ ...props
1032
+ }
1033
+ ));
1034
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
1035
+
1036
+ // src/desktop/select.tsx
1037
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1038
+ function Select({
1039
+ value,
1040
+ onValueChange,
1041
+ options,
1042
+ placeholder,
1043
+ size = "md",
1044
+ disabled,
1045
+ id,
1046
+ className,
1047
+ "aria-label": ariaLabel,
1048
+ ...data
1049
+ }) {
1050
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(SelectPrimitive2.Root, { ...value === void 0 ? {} : { value }, onValueChange, disabled: disabled ?? false, children: [
1051
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1052
+ SelectPrimitive2.Trigger,
1053
+ {
1054
+ ...data,
1055
+ id,
1056
+ "aria-label": ariaLabel,
1057
+ "data-slot": "select",
1058
+ className: cn(
1059
+ "focus-ring inline-flex min-w-0 items-center justify-between gap-2 rounded-control bg-control pl-2.5 pr-1.5 text-label shadow-control hover:bg-fill-secondary disabled:opacity-40 data-[placeholder]:text-label-tertiary",
1060
+ size === "sm" ? "h-control-sm text-callout" : "h-control text-body",
1061
+ className
1062
+ ),
1063
+ children: [
1064
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "min-w-0 truncate", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectPrimitive2.Value, { placeholder }) }),
1065
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectPrimitive2.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChevronsUpDownIcon, { className: "size-icon-sm shrink-0 text-label-secondary" }) })
1066
+ ]
1067
+ }
1068
+ ),
1069
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectContent, { children: options.map(
1070
+ (option, index) => option === "-" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectSeparator, {}, `sep-${index}`) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectItem, { value: option.value, disabled: option.disabled ?? false, children: option.label }, option.value)
1071
+ ) })
1072
+ ] });
1073
+ }
1074
+
1075
+ // src/desktop/segmented.tsx
1076
+ var ToggleGroup = __toESM(require("@radix-ui/react-toggle-group"), 1);
1077
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1078
+ function Segmented({
1079
+ value,
1080
+ onValueChange,
1081
+ segments,
1082
+ size = "md",
1083
+ className,
1084
+ "aria-label": ariaLabel,
1085
+ ...data
1086
+ }) {
1087
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1088
+ ToggleGroup.Root,
1089
+ {
1090
+ ...data,
1091
+ type: "single",
1092
+ value,
1093
+ "aria-label": ariaLabel,
1094
+ onValueChange: (next) => {
1095
+ if (next) onValueChange(next);
1096
+ },
1097
+ "data-slot": "segmented",
1098
+ className: cn(
1099
+ "inline-flex items-stretch gap-0.5 rounded-control bg-fill-secondary p-0.5",
1100
+ size === "sm" ? "h-control-sm text-callout" : "h-control text-body",
1101
+ className
1102
+ ),
1103
+ children: segments.map((segment) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1104
+ ToggleGroup.Item,
1105
+ {
1106
+ value: segment.value,
1107
+ "aria-label": segment.ariaLabel,
1108
+ disabled: segment.disabled,
1109
+ className: "focus-ring inline-flex min-w-0 flex-1 items-center justify-center gap-1 rounded-control px-2.5 text-label-secondary transition-colors duration-100 hover:text-label disabled:opacity-40 data-[state=on]:bg-control data-[state=on]:text-label data-[state=on]:shadow-control [&_svg]:size-icon-sm",
1110
+ children: segment.label
1111
+ },
1112
+ segment.value
1113
+ ))
1114
+ }
1115
+ );
1116
+ }
1117
+
1118
+ // src/switch.tsx
1119
+ var SwitchPrimitives = __toESM(require("@radix-ui/react-switch"), 1);
1120
+ var React7 = __toESM(require("react"), 1);
1121
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1122
+ var SWITCH_SIZES = {
1123
+ sm: {
1124
+ root: "h-4 w-9 border-border data-[state=unchecked]:bg-input",
1125
+ thumb: "h-4 w-4 border border-primary data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
1126
+ },
1127
+ md: {
1128
+ root: "h-5 w-9 border-transparent data-[state=unchecked]:bg-input",
1129
+ thumb: "h-4 w-4 data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
1130
+ }
1131
+ };
1132
+ var Switch = React7.forwardRef(({ className, size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1133
+ SwitchPrimitives.Root,
1134
+ {
1135
+ ref,
1136
+ "data-slot": "switch",
1137
+ className: cn2(
1138
+ "peer inline-flex shrink-0 items-center rounded-full border-2 shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary",
1139
+ SWITCH_SIZES[size].root,
1140
+ className
1141
+ ),
1142
+ ...props,
1143
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1144
+ SwitchPrimitives.Thumb,
1145
+ {
1146
+ "data-slot": "switch-thumb",
1147
+ className: cn2(
1148
+ "pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform",
1149
+ SWITCH_SIZES[size].thumb
1150
+ )
1151
+ }
1152
+ )
1153
+ }
1154
+ ));
1155
+ Switch.displayName = SwitchPrimitives.Root.displayName;
1156
+
1157
+ // src/checkbox.tsx
1158
+ var CheckboxPrimitive = __toESM(require("@radix-ui/react-checkbox"), 1);
1159
+ var React8 = __toESM(require("react"), 1);
1160
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1161
+ var CHECKBOX_SIZES = {
1162
+ sm: { root: "h-3.5 w-3.5 rounded-xs", glyph: "h-3 w-3" },
1163
+ md: { root: "h-4 w-4 rounded-sm", glyph: "h-3.5 w-3.5" }
1164
+ };
1165
+ var Checkbox = React8.forwardRef(({ className, size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1166
+ CheckboxPrimitive.Root,
1167
+ {
1168
+ ref,
1169
+ "data-slot": "checkbox",
1170
+ className: cn2(
1171
+ "peer shrink-0 border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
1172
+ CHECKBOX_SIZES[size].root,
1173
+ className
1174
+ ),
1175
+ ...props,
1176
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1177
+ CheckboxPrimitive.Indicator,
1178
+ {
1179
+ "data-slot": "checkbox-indicator",
1180
+ className: "flex items-center justify-center text-current",
1181
+ children: props.checked === "indeterminate" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DividerHorizontalIcon, { className: CHECKBOX_SIZES[size].glyph }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CheckIcon, { className: CHECKBOX_SIZES[size].glyph })
1182
+ }
1183
+ )
1184
+ }
1185
+ ));
1186
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
1187
+
1188
+ // src/desktop/layout.tsx
1189
+ var React9 = __toESM(require("react"), 1);
1190
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1191
+ var WIDTH = {
1192
+ form: "max-w-form",
1193
+ wide: "max-w-wide",
1194
+ full: "max-w-none"
1195
+ };
1196
+ var Page = React9.forwardRef(function Page2({ width = "wide", header, className, children, ...props }, ref) {
1197
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref, "data-slot": "page", className: cn("h-full overflow-y-auto bg-content", className), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: cn("mx-auto flex w-full flex-col gap-6 px-8 pb-10 pt-6", width === "full" ? WIDTH.full : WIDTH.wide), children: [
1198
+ header,
1199
+ width === "form" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("flex w-full flex-col gap-6", WIDTH.form), children }) : children
1200
+ ] }) });
1201
+ });
1202
+ function PageHeader({ title, subtitle, icon, actions, className, ...props }) {
1203
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("header", { "data-slot": "page-header", className: cn("flex min-h-control-lg items-center gap-3", className), ...props, children: [
1204
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "flex size-icon-xl shrink-0 items-center justify-center text-label-secondary [&_svg]:size-icon-lg", children: icon }) : null,
1205
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col", children: [
1206
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { as: "h1", variant: "title-2", truncate: true, children: title }),
1207
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { variant: "callout", tone: "secondary", truncate: true, "aria-hidden": subtitle ? void 0 : true, children: subtitle ?? "\xA0" })
1208
+ ] }),
1209
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex shrink-0 items-center gap-2", children: actions }) : null
1210
+ ] });
1211
+ }
1212
+ function Toolbar({ draggable, className, ...props }) {
1213
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1214
+ "div",
1215
+ {
1216
+ role: "toolbar",
1217
+ "data-slot": "toolbar",
1218
+ className: cn(
1219
+ "flex h-toolbar shrink-0 items-center gap-2 px-3 [&_button]:window-no-drag [&_input]:window-no-drag",
1220
+ draggable && "window-drag",
1221
+ className
1222
+ ),
1223
+ ...props
1224
+ }
1225
+ );
1226
+ }
1227
+ function ToolbarSpacer() {
1228
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { "aria-hidden": true, className: "flex-1" });
1229
+ }
1230
+ function ToolbarDivider() {
1231
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { "aria-hidden": true, className: "mx-1 h-icon w-px bg-separator" });
1232
+ }
1233
+
1234
+ // src/desktop/group.tsx
1235
+ var React10 = __toESM(require("react"), 1);
1236
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1237
+ function Section({ title, actions, footer, appearance = "grouped", className, children, ...props }) {
1238
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { "data-slot": "section", className: cn("flex flex-col gap-2", appearance === "grouped" && "max-w-form", className), ...props, children: [
1239
+ title || actions ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-h-control items-end gap-2", children: [
1240
+ title ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { as: "h2", variant: "headline", className: "flex-1", truncate: true, children: title }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex-1" }),
1241
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex items-center gap-2", children: actions }) : null
1242
+ ] }) : null,
1243
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1244
+ "div",
1245
+ {
1246
+ "data-appearance": appearance,
1247
+ className: cn(
1248
+ "flex flex-col [&>[data-slot=row]+[data-slot=row]]:before:block",
1249
+ appearance === "grouped" && "max-w-form overflow-hidden rounded-group bg-group shadow-raised"
1250
+ ),
1251
+ children
1252
+ }
1253
+ ),
1254
+ footer ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { as: "p", variant: "caption", tone: "secondary", children: footer }) : null
1255
+ ] });
1256
+ }
1257
+ function SectionContent({ className, ...props }) {
1258
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { "data-slot": "row", className: cn("relative px-3 py-3", className), ...props });
1259
+ }
1260
+ var Row = React10.forwardRef(function Row2({ icon, title, subtitle, value, accessory, chevron, onSelect, selected, disabled, destructive, mono, className, style, ...props }, ref) {
1261
+ const interactive = Boolean(onSelect) && !disabled;
1262
+ const body = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1263
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex size-icon-lg shrink-0 items-center justify-center text-label-secondary [&_svg]:size-icon", children: icon }) : null,
1264
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col", children: [
1265
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { tone: destructive ? "danger" : "primary", mono, truncate: true, className: cn(selected && "text-inherit"), children: title }),
1266
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { variant: "callout", tone: "secondary", truncate: true, className: cn(selected && "text-inherit opacity-80"), children: subtitle }) : null
1267
+ ] }),
1268
+ value !== void 0 && value !== null ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { tone: "secondary", tabular: true, truncate: true, className: cn("max-w-1/2 shrink-0 text-right", selected && "text-inherit opacity-80"), children: value }) : null,
1269
+ accessory ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1270
+ "span",
1271
+ {
1272
+ className: "flex shrink-0 items-center gap-2",
1273
+ onClick: (event) => event.stopPropagation(),
1274
+ onKeyDown: (event) => event.stopPropagation(),
1275
+ children: accessory
1276
+ }
1277
+ ) : null,
1278
+ chevron ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRightIcon, { "aria-hidden": true, className: "size-icon-sm shrink-0 text-label-tertiary" }) : null
1279
+ ] });
1280
+ const rowClass = cn(
1281
+ "relative flex w-full items-center gap-3 px-3 text-left before:absolute before:right-0 before:top-0 before:hidden before:h-px before:bg-separator",
1282
+ icon ? "before:left-11" : "before:left-3",
1283
+ subtitle ? "min-h-row-tall py-1.5" : "min-h-row py-1",
1284
+ disabled && "opacity-40",
1285
+ selected && "bg-selection text-selection-label",
1286
+ className
1287
+ );
1288
+ if (interactive) {
1289
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1290
+ "button",
1291
+ {
1292
+ ref,
1293
+ type: "button",
1294
+ "data-slot": "row",
1295
+ "aria-current": selected || void 0,
1296
+ onClick: onSelect,
1297
+ style,
1298
+ className: cn(rowClass, "focus-ring -outline-offset-3 transition-colors duration-100", !selected && "hover:bg-fill active:bg-fill-secondary"),
1299
+ ...props,
1300
+ children: body
1301
+ }
1302
+ );
1303
+ }
1304
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref, "data-slot": "row", style, className: rowClass, ...props, children: body });
1305
+ });
1306
+ function FieldRow({ label, field, action, onSubmit, stacked, className, ...props }) {
1307
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1308
+ "form",
1309
+ {
1310
+ "data-slot": "row",
1311
+ noValidate: true,
1312
+ onSubmit: (event) => {
1313
+ event.preventDefault();
1314
+ onSubmit?.();
1315
+ },
1316
+ className: cn(
1317
+ "relative flex min-h-row w-full gap-3 px-3 py-1.5 before:absolute before:left-3 before:right-0 before:top-0 before:hidden before:h-px before:bg-separator",
1318
+ stacked ? "flex-col py-3" : "items-center",
1319
+ className
1320
+ ),
1321
+ ...props,
1322
+ children: [
1323
+ label ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { variant: "body", className: "w-32 shrink-0", truncate: true, children: label }) : null,
1324
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "min-w-0 flex-1", children: field }),
1325
+ action ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("flex shrink-0 items-center gap-2", stacked && "self-end"), children: action }) : null
1326
+ ]
1327
+ }
1328
+ );
1329
+ }
1330
+
1331
+ // src/desktop/code-block.tsx
1332
+ var React11 = __toESM(require("react"), 1);
1333
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1334
+ function CodeBlock({ scroll = true, follow = false, className, children, ...props }) {
1335
+ const ref = React11.useRef(null);
1336
+ const pinned = React11.useRef(true);
1337
+ React11.useLayoutEffect(() => {
1338
+ const el = ref.current;
1339
+ if (follow && el && pinned.current) el.scrollTop = el.scrollHeight;
1340
+ }, [follow, children]);
1341
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1342
+ "pre",
1343
+ {
1344
+ ref,
1345
+ onScroll: (event) => {
1346
+ const el = event.currentTarget;
1347
+ pinned.current = el.scrollHeight - el.scrollTop - el.clientHeight < 8;
1348
+ },
1349
+ "data-slot": "code-block",
1350
+ className: cn(
1351
+ "m-0 select-text whitespace-pre-wrap break-words rounded-control bg-fill px-3 py-2 font-mono text-callout text-label",
1352
+ scroll && "max-h-80 overflow-y-auto",
1353
+ className
1354
+ ),
1355
+ ...props,
1356
+ children
1357
+ }
1358
+ );
1359
+ }
1360
+
1361
+ // src/desktop/table.tsx
1362
+ var React18 = __toESM(require("react"), 1);
1363
+
1364
+ // src/alert-dialog.tsx
1365
+ var AlertDialogPrimitive = __toESM(require("@radix-ui/react-alert-dialog"), 1);
1366
+ var import_react_tree = require("@ai-matrx/kit/react-tree");
1367
+ var React14 = __toESM(require("react"), 1);
1368
+
1369
+ // src/button.tsx
1370
+ var import_react_slot2 = require("@radix-ui/react-slot");
1371
+ var import_class_variance_authority3 = require("class-variance-authority");
1372
+ var React12 = __toESM(require("react"), 1);
1373
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1374
+ var buttonVariants2 = (0, import_class_variance_authority3.cva)(
1375
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:opacity-50 active:scale-[0.98] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1376
+ {
1377
+ variants: {
1378
+ variant: {
1379
+ default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
1380
+ /**
1381
+ * An explicit spelling of `default`, identical by construction. It is
1382
+ * not decoration: matrx-frontend's `ButtonMine` fork carried it, ~17
1383
+ * call sites say `variant="primary"`, and the alternative to keeping
1384
+ * the word was a host shim translating a prop — the massage C22 bans.
1385
+ */
1386
+ primary: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
1387
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
1388
+ /** The affirmative twin of `destructive` — confirm, approve, publish. */
1389
+ success: "bg-success text-success-foreground shadow-sm hover:bg-success/90",
1390
+ outline: "border border-border bg-card shadow-sm hover:bg-accent hover:text-accent-foreground",
1391
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
1392
+ ghost: "hover:bg-accent hover:text-accent-foreground",
1393
+ link: "text-primary underline-offset-4 hover:underline",
1394
+ subtle: "border border-transparent bg-muted/50 text-foreground hover:border-border hover:bg-muted"
1395
+ },
1396
+ /**
1397
+ * ONE size scale, xs → 3xl, plus the two icon boxes. The top and bottom
1398
+ * of the scale came in from matrx-frontend's `ButtonMine` fork (2026-09-07):
1399
+ * a dense toolbar needs `xs`, and a marketing/hero call to action needs
1400
+ * `xl`+. A host that has to reach outside this scale forks the button,
1401
+ * which is exactly how `ButtonMine` was born.
1402
+ */
1403
+ size: {
1404
+ xs: "h-6 rounded-md px-1 text-xs",
1405
+ sm: "h-8 rounded-md px-3 text-xs",
1406
+ default: "h-9 px-4 py-2",
1407
+ /** An explicit spelling of `default` (the fork's middle rung). */
1408
+ md: "h-9 px-4 py-2",
1409
+ lg: "h-10 rounded-md px-6",
1410
+ xl: "h-12 px-8 py-3 text-base",
1411
+ "2xl": "h-14 px-10 py-3 text-base",
1412
+ "3xl": "h-16 px-12 py-3 text-base",
1413
+ icon: "h-9 w-9",
1414
+ "icon-sm": "h-7 w-7",
1415
+ /** A circular icon box — an avatar-shaped control, not a square one. */
1416
+ roundIcon: "h-8 w-8 rounded-full p-0"
1417
+ }
1418
+ },
1419
+ defaultVariants: {
1420
+ variant: "default",
1421
+ size: "default"
1422
+ }
1423
+ }
1424
+ );
1425
+ var TOUCH_FLOOR_SIZES = /* @__PURE__ */ new Set([
1426
+ "xs",
1427
+ "sm",
1428
+ "default",
1429
+ "md",
1430
+ "lg",
1431
+ "icon",
1432
+ "icon-sm",
1433
+ "roundIcon"
1434
+ ]);
1435
+ var SQUARE_SIZES = /* @__PURE__ */ new Set(["icon", "icon-sm", "roundIcon"]);
1436
+ function swallowClick(event) {
1437
+ event.preventDefault();
1438
+ event.stopPropagation();
1439
+ }
1440
+ var Button3 = React12.forwardRef(
1441
+ ({ className, variant, size, asChild = false, onClick, ...props }, ref) => {
1442
+ const Component = asChild ? import_react_slot2.Slot : "button";
1443
+ const resolvedSize = size ?? "default";
1444
+ const disabledChild = asChild && Boolean(props.disabled);
1445
+ const ariaDisabled = props["aria-disabled"];
1446
+ const inert = disabledChild || ariaDisabled === true || ariaDisabled === "true";
1447
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1448
+ Component,
1449
+ {
1450
+ className: cn2(buttonVariants2({ variant, size, className })),
1451
+ "data-matrx-button": "",
1452
+ "data-tap-floor": TOUCH_FLOOR_SIZES.has(resolvedSize) ? "" : void 0,
1453
+ "data-tap-floor-square": SQUARE_SIZES.has(resolvedSize) ? "" : void 0,
1454
+ ref,
1455
+ ...props,
1456
+ "aria-disabled": disabledChild ? true : ariaDisabled,
1457
+ tabIndex: disabledChild ? -1 : props.tabIndex,
1458
+ onClick: inert ? swallowClick : onClick
1459
+ }
1460
+ );
1461
+ }
1462
+ );
1463
+ Button3.displayName = "Button";
1464
+
1465
+ // src/floating-layer.tsx
1466
+ var import_react_focus_scope = require("@radix-ui/react-focus-scope");
1467
+ var import_react_slot3 = require("@radix-ui/react-slot");
1468
+ var React13 = __toESM(require("react"), 1);
1469
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1470
+ var FLOATING_LAYER_ATTR = "data-matrx-floating-layer";
1471
+ var REGISTRY_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.modal-layer-registry");
1472
+ var registryHost = globalThis;
1473
+ var registry = registryHost[REGISTRY_SLOT] ??= {
1474
+ count: 0,
1475
+ listeners: /* @__PURE__ */ new Set()
1476
+ };
1477
+ function emit() {
1478
+ for (const listener of registry.listeners) listener();
1479
+ }
1480
+ var SCROLL_EVENTS = ["wheel", "touchmove"];
1481
+ function stopAtBody(event) {
1482
+ if (isInsideFloatingLayer(event.target)) event.stopPropagation();
1483
+ }
1484
+ function setScrollPassthrough(on) {
1485
+ if (typeof document === "undefined" || !document.body) return;
1486
+ for (const type of SCROLL_EVENTS) {
1487
+ if (on) document.body.addEventListener(type, stopAtBody, { passive: true });
1488
+ else document.body.removeEventListener(type, stopAtBody);
1489
+ }
1490
+ }
1491
+ function registerModalLayer() {
1492
+ registry.count += 1;
1493
+ if (registry.count === 1) setScrollPassthrough(true);
1494
+ emit();
1495
+ let released = false;
1496
+ return () => {
1497
+ if (released) return;
1498
+ released = true;
1499
+ registry.count = Math.max(0, registry.count - 1);
1500
+ if (registry.count === 0) setScrollPassthrough(false);
1501
+ emit();
1502
+ };
1503
+ }
1504
+ function isModalLayerOpen() {
1505
+ return registry.count > 0;
1506
+ }
1507
+ function useModalLayer(active) {
1508
+ React13.useLayoutEffect(() => active ? registerModalLayer() : void 0, [active]);
1509
+ }
1510
+ var POPPER_WRAPPER = "[data-radix-popper-content-wrapper]";
1511
+ function isInsideFloatingLayer(target) {
1512
+ if (!(target instanceof Element)) return false;
1513
+ if (target.closest(`[${FLOATING_LAYER_ATTR}]`)) return true;
1514
+ return target.closest(POPPER_WRAPPER) !== null && target.ownerDocument.querySelector(`[${FLOATING_LAYER_ATTR}]`) !== null;
1515
+ }
1516
+ function keepFloatingLayersInside(handler) {
1517
+ return (event) => {
1518
+ handler?.(event);
1519
+ if (isInsideFloatingLayer(event.target)) event.preventDefault();
1520
+ };
1521
+ }
1522
+ var preventAutoFocus = (event) => event.preventDefault();
1523
+ var FloatingLayer = React13.forwardRef(({ children }, ref) => {
1524
+ const [opener] = React13.useState(
1525
+ () => typeof document === "undefined" ? null : document.activeElement
1526
+ );
1527
+ const returnFocus = (event) => {
1528
+ event.preventDefault();
1529
+ const active = document.activeElement;
1530
+ const lost = !active || active === document.body || !active.isConnected;
1531
+ if (lost && isModalLayerOpen() && opener instanceof HTMLElement && opener.isConnected) {
1532
+ opener.focus({ preventScroll: true });
1533
+ }
1534
+ };
1535
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1536
+ import_react_focus_scope.FocusScope,
1537
+ {
1538
+ asChild: true,
1539
+ trapped: false,
1540
+ loop: false,
1541
+ onMountAutoFocus: preventAutoFocus,
1542
+ onUnmountAutoFocus: returnFocus,
1543
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1544
+ import_react_slot3.Slot,
1545
+ {
1546
+ ref,
1547
+ ...{ [FLOATING_LAYER_ATTR]: "" },
1548
+ style: { pointerEvents: "auto" },
1549
+ children
1550
+ }
1551
+ )
1552
+ }
1553
+ );
1554
+ });
1555
+ FloatingLayer.displayName = "FloatingLayer";
1556
+
1557
+ // src/alert-dialog.tsx
1558
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1559
+ var AlertDialog = AlertDialogPrimitive.Root;
1560
+ var AlertDialogPortal = ({
1561
+ container,
1562
+ ...props
1563
+ }) => {
1564
+ const resolved = usePortalContainer(container);
1565
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertDialogPrimitive.Portal, { container: resolved ?? null, ...props });
1566
+ };
1567
+ AlertDialogPortal.displayName = "AlertDialogPortal";
1568
+ var AlertDialogOverlay = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1569
+ AlertDialogPrimitive.Overlay,
1570
+ {
1571
+ ref,
1572
+ "data-slot": "alert-dialog-overlay",
1573
+ className: cn2(
1574
+ "fixed inset-0 z-[10000] bg-[var(--matrx-overlay-scrim)]",
1575
+ MOTION_OVERLAY,
1576
+ className
1577
+ ),
1578
+ ...props
1579
+ }
1580
+ ));
1581
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
1582
+ var AlertDialogContentPrimitive = React14.forwardRef((props, ref) => {
1583
+ useModalLayer(true);
1584
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertDialogPrimitive.Content, { ...props, ref, "aria-modal": "true" });
1585
+ });
1586
+ AlertDialogContentPrimitive.displayName = "AlertDialogContentPrimitive";
1587
+ var AlertDialogDescription = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1588
+ AlertDialogPrimitive.Description,
1589
+ {
1590
+ ref,
1591
+ "data-slot": "alert-dialog-description",
1592
+ className: cn2("text-sm text-muted-foreground", className),
1593
+ ...props
1594
+ }
1595
+ ));
1596
+ AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
1597
+ var AlertDialogContent = React14.forwardRef(({ className, children, container, animated = true, ...props }, ref) => {
1598
+ const hasDescription = (0, import_react_tree.treeContainsComponent)(children, AlertDialogDescription) || (0, import_react_tree.treeContainsComponent)(children, AlertDialogPrimitive.Description);
1599
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(AlertDialogPortal, { container, children: [
1600
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertDialogOverlay, {}),
1601
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1602
+ AlertDialogContentPrimitive,
1603
+ {
1604
+ ref,
1605
+ "data-slot": "alert-dialog-content",
1606
+ className: cn2(
1607
+ `matrx-dialog-card fixed left-[50%] top-[50%] z-[10000] grid min-w-0 w-full max-w-lg ${CENTERED_DIALOG} gap-4 border bg-background p-6 shadow-lg`,
1608
+ // Ruling 3 — never taller than the viewport, always scrollable, and
1609
+ // the footer stays reachable via --dialog-pad like Dialog's.
1610
+ // Ruling 5 (0.11.3) — `matrx-dialog-card` hands the bottom padding to
1611
+ // a sticky footer when there is one, so the footer's box matches the
1612
+ // space the grid gave it and sticky never clamps it up over the
1613
+ // consequence copy.
1614
+ "max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full",
1615
+ "sm:rounded-lg",
1616
+ animated && MOTION_DIALOG,
1617
+ className
1618
+ ),
1619
+ ...props,
1620
+ children: [
1621
+ hasDescription ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertDialogPrimitive.Description, { className: "sr-only", children: "Please confirm the action described in this dialog." }),
1622
+ children
1623
+ ]
1624
+ }
1625
+ )
1626
+ ] });
1627
+ });
1628
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
1629
+ var AlertDialogHeader = ({
1630
+ className,
1631
+ ...props
1632
+ }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1633
+ "div",
1634
+ {
1635
+ "data-slot": "alert-dialog-header",
1636
+ className: cn2("flex flex-col space-y-2 text-center sm:text-left", className),
1637
+ ...props
1638
+ }
1639
+ );
1640
+ AlertDialogHeader.displayName = "AlertDialogHeader";
1641
+ var AlertDialogFooter = ({
1642
+ className,
1643
+ ...props
1644
+ }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1645
+ "div",
1646
+ {
1647
+ "data-slot": "alert-dialog-footer",
1648
+ className: cn2(
1649
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
1650
+ // Ruling 3/4 — sticky to the card edges so a scrolled body never shows
1651
+ // through under the actions, and safe-area padded on a phone.
1652
+ //
1653
+ // 🚨 THERE IS NO `mb-[…]` HERE, AND THERE MUST NEVER BE ONE AGAIN
1654
+ // (0.11.3, feedback bf8fb00b). The bleed over the card's bottom padding
1655
+ // used to be a NEGATIVE BLOCK MARGIN, which makes this box taller than
1656
+ // the grid area the card allocates it — and `position: sticky` CLAMPS a
1657
+ // box to its containing block, so the browser yanked the footer UP by
1658
+ // `--dialog-pad` against the card's `gap-4` and painted 8px of opaque
1659
+ // footer over the last line of the consequence, at every length. The
1660
+ // card now RESERVES this footer's block size instead (`matrx-dialog-card`
1661
+ // in styles.css hands over its `padding-bottom`), so the bleed costs no
1662
+ // margin at all. Guard: `sticky-footer-geometry.test.tsx`.
1663
+ //
1664
+ // These stay UTILITIES rather than a shipped rule so a caller's
1665
+ // `className` still wins through tailwind-merge — a shipped rule would
1666
+ // have to be unlayered to survive Tailwind preflight (§ THE PREFLIGHT
1667
+ // RULE in styles.css) and would then override every caller's padding.
1668
+ "sticky bottom-0 z-10 bg-background pt-3",
1669
+ "mx-[calc(var(--dialog-pad,0px)*-1)] px-[var(--dialog-pad,0px)] pb-[var(--dialog-pad,0px)]",
1670
+ className
1671
+ ),
1672
+ ...props
1673
+ }
1674
+ );
1675
+ AlertDialogFooter.displayName = "AlertDialogFooter";
1676
+ var AlertDialogTitle = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1677
+ AlertDialogPrimitive.Title,
1678
+ {
1679
+ ref,
1680
+ "data-slot": "alert-dialog-title",
1681
+ className: cn2("text-lg font-semibold", className),
1682
+ ...props
1683
+ }
1684
+ ));
1685
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
1686
+ var AlertDialogAction = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1687
+ AlertDialogPrimitive.Action,
1688
+ {
1689
+ ref,
1690
+ "data-slot": "alert-dialog-action",
1691
+ className: cn2(buttonVariants2(), className),
1692
+ ...props
1693
+ }
1694
+ ));
1695
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
1696
+ var AlertDialogCancel = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1697
+ AlertDialogPrimitive.Cancel,
1698
+ {
1699
+ ref,
1700
+ "data-slot": "alert-dialog-cancel",
1701
+ className: cn2(
1702
+ buttonVariants2({ variant: "outline" }),
1703
+ "mt-2 sm:mt-0",
1704
+ className
1705
+ ),
1706
+ ...props
1707
+ }
1708
+ ));
1709
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
1710
+
1711
+ // src/confirm-dialog.tsx
1712
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1713
+ function ConfirmDialog({
1714
+ open,
1715
+ onOpenChange,
1716
+ title,
1717
+ description,
1718
+ content,
1719
+ contentClassName,
1720
+ confirmLabel = "Confirm",
1721
+ cancelLabel = "Cancel",
1722
+ variant = "default",
1723
+ busy = false,
1724
+ confirmDisabled = false,
1725
+ confirmHeld = false,
1726
+ portalContainer,
1727
+ onConfirm
1728
+ }) {
1729
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AlertDialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1730
+ AlertDialogContent,
1731
+ {
1732
+ className: contentClassName,
1733
+ ...portalContainer === void 0 ? {} : { container: portalContainer },
1734
+ children: [
1735
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(AlertDialogHeader, { children: [
1736
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AlertDialogTitle, { children: title }),
1737
+ description ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AlertDialogDescription, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { children: description }) }) : null
1738
+ ] }),
1739
+ content ?? null,
1740
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(AlertDialogFooter, { children: [
1741
+ cancelLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AlertDialogCancel, { className: "max-lg:min-h-11", disabled: busy, children: cancelLabel }),
1742
+ confirmHeld ? null : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1743
+ AlertDialogAction,
1744
+ {
1745
+ disabled: busy || confirmDisabled,
1746
+ onClick: (event) => {
1747
+ event.preventDefault();
1748
+ void onConfirm();
1749
+ },
1750
+ className: cn2(
1751
+ "max-lg:min-h-11",
1752
+ // One source of button appearance: the destructive look comes
1753
+ // from `buttonVariants`, not a second hand-written copy of it.
1754
+ // tailwind-merge makes it WIN over the default variant classes.
1755
+ variant === "destructive" && buttonVariants2({ variant: "destructive" })
1756
+ ),
1757
+ children: [
1758
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Loader2Icon, { className: cn2("mr-2 h-4 w-4", MOTION_SPIN) }) : null,
1759
+ confirmLabel
1760
+ ]
1761
+ }
1762
+ )
1763
+ ] })
1764
+ ]
1765
+ }
1766
+ ) });
1767
+ }
1768
+
1769
+ // src/dropdown-menu.tsx
1770
+ var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
1771
+ var React17 = __toESM(require("react"), 1);
1772
+
1773
+ // src/menu-scroll-edges.tsx
1774
+ var React15 = __toESM(require("react"), 1);
1775
+
1776
+ // src/use-scroll-fade.ts
1777
+ var import_react = require("react");
1778
+ var EPSILON = 2;
1779
+ function useScrollFade() {
1780
+ const [state, setState] = (0, import_react.useState)({
1781
+ top: false,
1782
+ bottom: false
1783
+ });
1784
+ const nodeRef = (0, import_react.useRef)(null);
1785
+ const cleanupRef = (0, import_react.useRef)(null);
1786
+ const measure = (0, import_react.useCallback)(() => {
1787
+ const el = nodeRef.current;
1788
+ if (!el) return;
1789
+ const overflowing = el.scrollHeight - el.clientHeight > EPSILON;
1790
+ const next = {
1791
+ top: overflowing && el.scrollTop > EPSILON,
1792
+ bottom: overflowing && el.scrollTop + el.clientHeight < el.scrollHeight - EPSILON
1793
+ };
1794
+ setState(
1795
+ (prev) => prev.top === next.top && prev.bottom === next.bottom ? prev : next
1796
+ );
1797
+ }, []);
1798
+ const ref = (0, import_react.useCallback)(
1799
+ (node) => {
1800
+ cleanupRef.current?.();
1801
+ cleanupRef.current = null;
1802
+ nodeRef.current = node;
1803
+ if (!node) return;
1804
+ node.addEventListener("scroll", measure, { passive: true });
1805
+ const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
1806
+ ro?.observe(node);
1807
+ const mo = new MutationObserver(measure);
1808
+ mo.observe(node, { childList: true, subtree: true });
1809
+ cleanupRef.current = () => {
1810
+ node.removeEventListener("scroll", measure);
1811
+ ro?.disconnect();
1812
+ mo.disconnect();
1813
+ };
1814
+ requestAnimationFrame(measure);
1815
+ },
1816
+ [measure]
1817
+ );
1818
+ (0, import_react.useEffect)(() => () => cleanupRef.current?.(), []);
1819
+ return {
1820
+ ref,
1821
+ state,
1822
+ fadeProps: {
1823
+ "data-fade-top": state.top ? "" : void 0,
1824
+ "data-fade-bottom": state.bottom ? "" : void 0,
1825
+ className: "matrx-scroll-fade"
1826
+ }
1827
+ };
1828
+ }
1829
+
1830
+ // src/menu-scroll-edges.tsx
1831
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1832
+ var HOVER_SPEED = 0.6;
1833
+ var PAGE_OVERLAP = 48;
1834
+ function composeRefs(...refs) {
1835
+ return (node) => {
1836
+ for (const ref of refs) {
1837
+ if (typeof ref === "function") ref(node);
1838
+ else if (ref) ref.current = node;
1839
+ }
1840
+ };
1841
+ }
1842
+ function MenuScrollEdge({ side, scroller }) {
1843
+ const frame = React15.useRef(null);
1844
+ const dir = side === "top" ? -1 : 1;
1845
+ const stop = React15.useCallback(() => {
1846
+ if (frame.current !== null) cancelAnimationFrame(frame.current);
1847
+ frame.current = null;
1848
+ }, []);
1849
+ const glide = React15.useCallback(() => {
1850
+ stop();
1851
+ let last = performance.now();
1852
+ const step = (now) => {
1853
+ const el = scroller.current;
1854
+ if (!el) return stop();
1855
+ el.scrollTop += dir * HOVER_SPEED * (now - last);
1856
+ last = now;
1857
+ frame.current = requestAnimationFrame(step);
1858
+ };
1859
+ frame.current = requestAnimationFrame(step);
1860
+ }, [dir, scroller, stop]);
1861
+ React15.useEffect(() => stop, [stop]);
1862
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { "aria-hidden": true, "data-menu-scroll-edge": side, className: "matrx-menu-scroll-edge", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "matrx-menu-scroll-fade", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1863
+ "div",
1864
+ {
1865
+ "data-menu-scroll-button": "",
1866
+ className: "matrx-menu-scroll-button",
1867
+ onPointerEnter: (e) => {
1868
+ if (e.pointerType !== "touch") glide();
1869
+ },
1870
+ onPointerLeave: stop,
1871
+ onPointerDown: (e) => {
1872
+ e.preventDefault();
1873
+ const el = scroller.current;
1874
+ if (!el) return;
1875
+ el.scrollTop += dir * Math.max(el.clientHeight - PAGE_OVERLAP, PAGE_OVERLAP);
1876
+ },
1877
+ children: side === "top" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(RadixChevronUpIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(RadixChevronDownIcon, {})
1878
+ }
1879
+ ) }) });
1880
+ }
1881
+ function useMenuScrollEdges(...forwarded) {
1882
+ const fade = useScrollFade();
1883
+ const scroller = React15.useRef(null);
1884
+ const ref = React15.useCallback(composeRefs(scroller, fade.ref, ...forwarded), [
1885
+ fade.ref,
1886
+ ...forwarded
1887
+ ]);
1888
+ const wrap = (children) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
1889
+ fade.state.top ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MenuScrollEdge, { side: "top", scroller }) : null,
1890
+ children,
1891
+ fade.state.bottom ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MenuScrollEdge, { side: "bottom", scroller }) : null
1892
+ ] });
1893
+ return { ref, wrap, surfaceClassName: "matrx-menu-surface" };
1894
+ }
1895
+
1896
+ // src/submenu-focus.ts
1897
+ var React16 = __toESM(require("react"), 1);
1898
+ function useSubmenuSurvivesParentPanelFocus(forwardedRef, onFocusOutside) {
1899
+ const content = React16.useRef(null);
1900
+ const ref = React16.useCallback(
1901
+ (node) => {
1902
+ content.current = node;
1903
+ if (typeof forwardedRef === "function") forwardedRef(node);
1904
+ else if (forwardedRef) forwardedRef.current = node;
1905
+ },
1906
+ [forwardedRef]
1907
+ );
1908
+ const handle = (event) => {
1909
+ onFocusOutside?.(event);
1910
+ if (event.defaultPrevented) return;
1911
+ const to = event.target;
1912
+ const id = content.current?.id;
1913
+ if (!(to instanceof Element) || !id || to.getAttribute("role") !== "menu") return;
1914
+ const holdsTrigger = Array.from(to.querySelectorAll("[aria-controls]")).some((el) => el.getAttribute("aria-controls") === id);
1915
+ if (holdsTrigger) event.preventDefault();
1916
+ };
1917
+ return { ref, onFocusOutside: handle };
1918
+ }
1919
+
1920
+ // src/dropdown-menu.tsx
1921
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1922
+ var DropdownMenu = DropdownMenuPrimitive.Root;
1923
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
1924
+ var DropdownMenuGroup = DropdownMenuPrimitive.Group;
1925
+ var DropdownMenuSub = DropdownMenuPrimitive.Sub;
1926
+ var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
1927
+ var MENU_SURFACE_CLASS = "z-[10001] min-w-[8rem] max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto overflow-x-hidden overscroll-contain rounded-md border bg-popover p-1 text-popover-foreground";
1928
+ var MENU_ITEM_CLASS = "relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:opacity-50";
1929
+ var MENU_INDICATOR_ITEM_CLASS = "relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:opacity-50";
1930
+ var DropdownMenuSubTrigger = React17.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1931
+ DropdownMenuPrimitive.SubTrigger,
1932
+ {
1933
+ ref,
1934
+ "data-slot": "dropdown-menu-sub-trigger",
1935
+ className: cn2(
1936
+ "flex select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
1937
+ inset && "pl-8",
1938
+ className
1939
+ ),
1940
+ ...props,
1941
+ children: [
1942
+ children,
1943
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RadixChevronRightIcon, { className: "ml-auto h-4 w-4" })
1944
+ ]
1945
+ }
1946
+ ));
1947
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
1948
+ var DropdownMenuSubContent = React17.forwardRef(({ className, container, sideOffset = 2, alignOffset = -4, collisionPadding = 8, onFocusOutside, children, ...props }, ref) => {
1949
+ const portalContainer = usePortalContainer(container);
1950
+ const keep = useSubmenuSurvivesParentPanelFocus(ref, onFocusOutside);
1951
+ const edges = useMenuScrollEdges(keep.ref);
1952
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1953
+ DropdownMenuPrimitive.SubContent,
1954
+ {
1955
+ ref: edges.ref,
1956
+ onFocusOutside: keep.onFocusOutside,
1957
+ "data-slot": "dropdown-menu-sub-content",
1958
+ sideOffset,
1959
+ alignOffset,
1960
+ collisionPadding,
1961
+ className: cn2(MENU_SURFACE_CLASS, edges.surfaceClassName, "shadow-lg", MOTION_POPPER, className),
1962
+ ...props,
1963
+ children: edges.wrap(children)
1964
+ }
1965
+ ) });
1966
+ });
1967
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
1968
+ var DropdownMenuContent = React17.forwardRef(({ className, sideOffset = 4, container, children, ...props }, ref) => {
1969
+ const portalContainer = usePortalContainer(container);
1970
+ const edges = useMenuScrollEdges(ref);
1971
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1972
+ DropdownMenuPrimitive.Content,
1973
+ {
1974
+ ref: edges.ref,
1975
+ "data-slot": "dropdown-menu-content",
1976
+ sideOffset,
1977
+ className: cn2(
1978
+ MENU_SURFACE_CLASS,
1979
+ edges.surfaceClassName,
1980
+ "shadow-md",
1981
+ MOTION_POPPER,
1982
+ className
1983
+ ),
1984
+ ...props,
1985
+ children: edges.wrap(children)
1986
+ }
1987
+ ) });
1988
+ });
1989
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
1990
+ var DropdownMenuItem = React17.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1991
+ DropdownMenuPrimitive.Item,
1992
+ {
1993
+ ref,
1994
+ "data-slot": "dropdown-menu-item",
1995
+ className: cn2(MENU_ITEM_CLASS, inset && "pl-8", className),
1996
+ ...props
1997
+ }
1998
+ ));
1999
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
2000
+ var DropdownMenuCheckboxItem = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2001
+ DropdownMenuPrimitive.CheckboxItem,
2002
+ {
2003
+ ref,
2004
+ "data-slot": "dropdown-menu-checkbox-item",
2005
+ className: cn2(MENU_INDICATOR_ITEM_CLASS, className),
2006
+ ...props,
2007
+ children: [
2008
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CheckIcon, { className: "h-4 w-4" }) }) }),
2009
+ children
2010
+ ]
2011
+ }
2012
+ ));
2013
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
2014
+ var DropdownMenuRadioItem = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2015
+ DropdownMenuPrimitive.RadioItem,
2016
+ {
2017
+ ref,
2018
+ "data-slot": "dropdown-menu-radio-item",
2019
+ className: cn2(MENU_INDICATOR_ITEM_CLASS, className),
2020
+ ...props,
2021
+ children: [
2022
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DotFilledIcon, { className: "h-4 w-4 fill-current" }) }) }),
2023
+ children
2024
+ ]
2025
+ }
2026
+ ));
2027
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
2028
+ var DropdownMenuLabel = React17.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2029
+ DropdownMenuPrimitive.Label,
2030
+ {
2031
+ ref,
2032
+ "data-slot": "dropdown-menu-label",
2033
+ className: cn2("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
2034
+ ...props
2035
+ }
2036
+ ));
2037
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
2038
+ var DropdownMenuSeparator = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2039
+ DropdownMenuPrimitive.Separator,
2040
+ {
2041
+ ref,
2042
+ "data-slot": "dropdown-menu-separator",
2043
+ className: cn2("-mx-1 my-1 h-px bg-muted", className),
2044
+ ...props
2045
+ }
2046
+ ));
2047
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
2048
+ var DropdownMenuShortcut = ({
2049
+ className,
2050
+ ...props
2051
+ }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2052
+ "span",
2053
+ {
2054
+ "data-slot": "dropdown-menu-shortcut",
2055
+ className: cn2("ml-auto text-xs tracking-widest opacity-60", className),
2056
+ ...props
2057
+ }
2058
+ );
2059
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
2060
+
2061
+ // src/desktop/table.tsx
2062
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2063
+ var WIDTH2 = { auto: "", fit: "w-px whitespace-nowrap", xs: "w-16", sm: "w-24", md: "w-36", lg: "w-56" };
2064
+ var ALIGN = { start: "text-left", end: "text-right", center: "text-center" };
2065
+ var CONTROL_TAGS = /* @__PURE__ */ new Set(["BUTTON", "A", "INPUT", "SELECT", "TEXTAREA"]);
2066
+ function insideControl(target, row) {
2067
+ for (let el = target; el && el !== row; el = el.parentElement) {
2068
+ if (CONTROL_TAGS.has(el.tagName) || el.getAttribute("role") === "menuitem") return true;
2069
+ }
2070
+ return false;
2071
+ }
2072
+ function DataTable({
2073
+ columns,
2074
+ rows,
2075
+ rowKey,
2076
+ onRowSelect,
2077
+ selectedKey,
2078
+ empty,
2079
+ striped = true,
2080
+ detail,
2081
+ isDisabled,
2082
+ rowAction,
2083
+ rowMenu,
2084
+ defaultSort,
2085
+ rowData,
2086
+ className,
2087
+ "aria-label": ariaLabel,
2088
+ ...rest
2089
+ }) {
2090
+ const bodyRef = React18.useRef(null);
2091
+ const [expanded, setExpanded] = React18.useState(() => /* @__PURE__ */ new Set());
2092
+ const toggle = (key, open) => setExpanded((prev) => {
2093
+ const next = new Set(prev);
2094
+ if (open ?? !next.has(key)) next.add(key);
2095
+ else next.delete(key);
2096
+ return next;
2097
+ });
2098
+ const [sort, setSort] = React18.useState(defaultSort ?? null);
2099
+ const sortColumn = sort ? columns.find((c) => c.key === sort.key && c.sort) : void 0;
2100
+ const ordered = React18.useMemo(() => {
2101
+ if (!sort || !sortColumn?.sort) return rows;
2102
+ const by = sortColumn.sort;
2103
+ const sign = sort.direction === "ascending" ? 1 : -1;
2104
+ return [...rows].sort((a, b) => sign * by(a, b));
2105
+ }, [rows, sort, sortColumn]);
2106
+ const toggleSort = (key) => setSort((prev) => prev?.key === key ? { key, direction: prev.direction === "ascending" ? "descending" : "ascending" } : { key, direction: "descending" });
2107
+ const hasActions = Boolean(rowAction || rowMenu);
2108
+ const span = columns.length + (detail ? 1 : 0) + (hasActions ? 1 : 0);
2109
+ const moveFocus = (event, delta) => {
2110
+ const rowsEls = Array.from(bodyRef.current?.rows ?? []).filter((tr) => tr.tabIndex >= 0);
2111
+ const next = rowsEls[rowsEls.indexOf(event.currentTarget) + delta];
2112
+ if (next) {
2113
+ event.preventDefault();
2114
+ next.focus();
2115
+ }
2116
+ };
2117
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-slot": "data-table", className: cn("overflow-hidden rounded-group bg-content shadow-raised", className), ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("table", { "aria-label": ariaLabel, className: "w-full table-auto border-collapse text-body", children: [
2118
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("tr", { className: "h-row-compact border-b border-separator", children: [
2119
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { "aria-hidden": true, className: "w-6" }) : null,
2120
+ columns.map((column) => {
2121
+ const sorted = sort?.key === column.key ? sort.direction : void 0;
2122
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2123
+ "th",
2124
+ {
2125
+ scope: "col",
2126
+ "aria-sort": column.sort ? sorted ?? "none" : void 0,
2127
+ className: cn(
2128
+ "px-3 text-caption font-medium text-label-secondary",
2129
+ WIDTH2[column.width ?? "auto"],
2130
+ ALIGN[column.align ?? (column.numeric ? "end" : "start")]
2131
+ ),
2132
+ children: column.sort ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2133
+ "button",
2134
+ {
2135
+ type: "button",
2136
+ onClick: () => toggleSort(column.key),
2137
+ className: cn(
2138
+ "focus-ring inline-flex items-center gap-1 rounded-control hover:text-label",
2139
+ sorted && "text-label",
2140
+ (column.align ?? (column.numeric ? "end" : "start")) === "end" && "flex-row-reverse"
2141
+ ),
2142
+ children: [
2143
+ column.header,
2144
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2145
+ ChevronDownIcon,
2146
+ {
2147
+ "aria-hidden": true,
2148
+ className: cn("size-2.5 transition-transform duration-100", !sorted && "invisible", sorted === "ascending" && "rotate-180")
2149
+ }
2150
+ )
2151
+ ]
2152
+ }
2153
+ ) : column.header
2154
+ },
2155
+ column.key
2156
+ );
2157
+ }),
2158
+ hasActions ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { "aria-label": "Actions", className: "w-px" }) : null
2159
+ ] }) }),
2160
+ rows.length === 0 && empty ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tbody", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { colSpan: span, children: empty }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tbody", { ref: bodyRef, children: ordered.map((row, index) => {
2161
+ const key = rowKey(row);
2162
+ const selected = selectedKey === key;
2163
+ const disabled = isDisabled?.(row) ?? false;
2164
+ const content = detail && !disabled ? detail(row) : null;
2165
+ const open = content !== null && expanded.has(key);
2166
+ const activate = onRowSelect ? () => onRowSelect(row) : content !== null ? () => toggle(key) : void 0;
2167
+ const focusable = Boolean(activate) && !disabled;
2168
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(React18.Fragment, { children: [
2169
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2170
+ "tr",
2171
+ {
2172
+ ...rowData?.(row),
2173
+ tabIndex: focusable ? 0 : void 0,
2174
+ "aria-selected": onRowSelect ? selected : void 0,
2175
+ "aria-expanded": content !== null ? open : void 0,
2176
+ "aria-disabled": disabled || void 0,
2177
+ "data-row-key": key,
2178
+ onClick: focusable ? (event) => {
2179
+ if (insideControl(event.target, event.currentTarget)) return;
2180
+ activate?.();
2181
+ } : void 0,
2182
+ onKeyDown: focusable ? (event) => {
2183
+ if (event.key === "Enter" || event.key === " ") {
2184
+ event.preventDefault();
2185
+ activate?.();
2186
+ } else if (event.key === "ArrowDown") moveFocus(event, 1);
2187
+ else if (event.key === "ArrowUp") moveFocus(event, -1);
2188
+ else if (event.key === "ArrowRight" && content !== null) toggle(key, true);
2189
+ else if (event.key === "ArrowLeft" && content !== null) toggle(key, false);
2190
+ } : void 0,
2191
+ className: cn(
2192
+ "group/row h-row-compact",
2193
+ striped && index % 2 === 1 && "bg-fill",
2194
+ focusable && "focus-ring -outline-offset-3",
2195
+ disabled && "text-label-tertiary",
2196
+ selected && "bg-selection text-selection-label"
2197
+ ),
2198
+ children: [
2199
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "w-6 pl-2", children: content !== null ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2200
+ ChevronRightIcon,
2201
+ {
2202
+ "aria-hidden": true,
2203
+ className: cn("size-icon-sm text-label-secondary transition-transform duration-100", open && "rotate-90")
2204
+ }
2205
+ ) : null }) : null,
2206
+ columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2207
+ "td",
2208
+ {
2209
+ className: cn(
2210
+ "max-w-0 truncate px-3",
2211
+ WIDTH2[column.width ?? "auto"],
2212
+ ALIGN[column.align ?? (column.numeric ? "end" : "start")],
2213
+ column.numeric && "tabular-nums",
2214
+ column.mono && "font-mono text-callout",
2215
+ column.width === "fit" && "max-w-none"
2216
+ ),
2217
+ children: column.cell(row)
2218
+ },
2219
+ column.key
2220
+ )),
2221
+ hasActions ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2222
+ "td",
2223
+ {
2224
+ className: cn(
2225
+ "w-px whitespace-nowrap px-2",
2226
+ // Finder: a row's buttons appear on hover, keyboard focus or selection only.
2227
+ !selected && "opacity-0 group-hover/row:opacity-100 group-focus-within/row:opacity-100 has-[[data-state=open]]:opacity-100"
2228
+ ),
2229
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RowActions, { action: rowAction?.(row) ?? null, menu: rowMenu?.(row) ?? null })
2230
+ }
2231
+ ) : null
2232
+ ]
2233
+ }
2234
+ ),
2235
+ open ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tr", { className: cn(striped && index % 2 === 1 && "bg-fill"), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { colSpan: span, className: "px-3 pb-2 pl-9", children: content }) }) : null
2236
+ ] }, key);
2237
+ }) })
2238
+ ] }) });
2239
+ }
2240
+ function RowActions({ action, menu }) {
2241
+ const [asking, setAsking] = React18.useState(null);
2242
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "flex items-center justify-end gap-1", children: [
2243
+ action ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { size: "sm", disabled: action.disabled ?? false, onClick: action.onSelect, children: action.label }) : null,
2244
+ menu && menu.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenu, { children: [
2245
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(IconButton, { size: "sm", label: "More", icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MoreHorizontalIcon, {}) }) }),
2246
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuContent, { align: "end", children: menu.map((item) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2247
+ DropdownMenuItem,
2248
+ {
2249
+ disabled: item.disabled ?? false,
2250
+ onSelect: () => item.destructive && item.confirm ? setAsking(item) : item.onSelect(),
2251
+ className: item.destructive ? "text-system-red focus:text-system-red" : void 0,
2252
+ children: item.label
2253
+ },
2254
+ item.label
2255
+ )) })
2256
+ ] }) : null,
2257
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2258
+ ConfirmDialog,
2259
+ {
2260
+ open: asking !== null,
2261
+ onOpenChange: (open) => open ? void 0 : setAsking(null),
2262
+ title: asking?.confirm ?? "",
2263
+ confirmLabel: asking?.label,
2264
+ variant: "destructive",
2265
+ onConfirm: () => {
2266
+ asking?.onSelect();
2267
+ setAsking(null);
2268
+ }
2269
+ }
2270
+ )
2271
+ ] });
2272
+ }
2273
+
2274
+ // src/desktop/source-list.tsx
2275
+ var React19 = __toESM(require("react"), 1);
2276
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2277
+ function SourceList({ className, onKeyDown, ...props }) {
2278
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2279
+ "nav",
2280
+ {
2281
+ "data-slot": "source-list",
2282
+ className: cn("flex min-h-0 flex-col gap-3 px-2", className),
2283
+ onKeyDown: (event) => {
2284
+ onKeyDown?.(event);
2285
+ if (event.defaultPrevented) return;
2286
+ const keys = ["ArrowDown", "ArrowUp", "Home", "End"];
2287
+ if (!keys.includes(event.key)) return;
2288
+ const items = Array.from(event.currentTarget.querySelectorAll("[data-slot=source-list-item]:not(:disabled)"));
2289
+ const at = items.indexOf(document.activeElement);
2290
+ if (at === -1) return;
2291
+ const next = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : at + (event.key === "ArrowDown" ? 1 : -1);
2292
+ const target = items[Math.max(0, Math.min(items.length - 1, next))];
2293
+ if (target) {
2294
+ event.preventDefault();
2295
+ target.focus();
2296
+ }
2297
+ },
2298
+ ...props
2299
+ }
2300
+ );
2301
+ }
2302
+ function SourceListSection({ title, action, className, children, ...props }) {
2303
+ const id = React19.useId();
2304
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { role: "group", "aria-labelledby": title ? id : void 0, "data-slot": "source-list-section", className: cn("flex flex-col", className), ...props, children: [
2305
+ title || action ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex h-row-compact items-center gap-2 px-2", children: [
2306
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text, { id, variant: "caption", tone: "tertiary", emphasized: true, className: "flex-1", truncate: true, children: title }),
2307
+ action
2308
+ ] }) : null,
2309
+ children
2310
+ ] });
2311
+ }
2312
+ var SourceListItem = React19.forwardRef(function SourceListItem2({ icon, label, hint, badge, current, className, type = "button", ...props }, ref) {
2313
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2314
+ "button",
2315
+ {
2316
+ ref,
2317
+ type,
2318
+ "data-slot": "source-list-item",
2319
+ "data-current": current || void 0,
2320
+ "aria-current": current ? "page" : void 0,
2321
+ className: cn(
2322
+ "focus-ring group/item flex w-full items-center gap-2 rounded-control px-2 text-left text-body text-label transition-colors duration-100 hover:bg-fill disabled:opacity-40",
2323
+ hint ? "min-h-row py-1" : "h-sidebar-row",
2324
+ current && "bg-selection-muted font-medium hover:bg-selection-muted [[data-window-active=false]_&]:bg-fill",
2325
+ className
2326
+ ),
2327
+ ...props,
2328
+ children: [
2329
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: cn("flex size-icon shrink-0 items-center justify-center text-label-secondary [&_svg]:size-icon", hint && "self-start mt-px"), children: icon }) : null,
2330
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col", children: [
2331
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "truncate", children: label }),
2332
+ hint ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "truncate text-callout font-normal text-label-secondary", children: hint }) : null
2333
+ ] }),
2334
+ badge ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "flex shrink-0 items-center text-callout tabular-nums text-label-tertiary", children: badge }) : null
2335
+ ]
2336
+ }
2337
+ );
2338
+ });
2339
+ function SourceListMore({ expanded, onToggle, className, ...props }) {
2340
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2341
+ "button",
2342
+ {
2343
+ ...props,
2344
+ type: "button",
2345
+ "data-slot": "source-list-more",
2346
+ "aria-expanded": expanded,
2347
+ onClick: onToggle,
2348
+ className: cn("focus-ring flex h-sidebar-row w-full items-center rounded-control px-2 text-left text-callout text-label-tertiary hover:text-label-secondary", className),
2349
+ children: expanded ? "Show less" : "Show more"
2350
+ }
2351
+ );
2352
+ }
2353
+
2354
+ // src/desktop/state.tsx
2355
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2356
+ function StateView({ kind, icon, title, message, actions, size = "inline", className, ...props }) {
2357
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2358
+ "div",
2359
+ {
2360
+ role: kind === "error" ? "alert" : kind === "loading" ? "status" : void 0,
2361
+ "aria-busy": kind === "loading" || void 0,
2362
+ "data-slot": "state-view",
2363
+ "data-kind": kind,
2364
+ className: cn(
2365
+ "flex flex-col items-center justify-center gap-2 px-6 text-center",
2366
+ size === "page" ? "h-full min-h-60 py-16" : "py-10",
2367
+ className
2368
+ ),
2369
+ ...props,
2370
+ children: [
2371
+ kind === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Spinner, { size: "lg" }) : icon ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2372
+ "span",
2373
+ {
2374
+ className: cn(
2375
+ "mb-1 flex items-center justify-center [&_svg]:size-icon-xl",
2376
+ kind === "error" ? "text-system-red" : "text-label-tertiary"
2377
+ ),
2378
+ children: icon
2379
+ }
2380
+ ) : null,
2381
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { variant: size === "page" ? "title-3" : "headline", tone: kind === "loading" ? "secondary" : "primary", children: title }),
2382
+ message ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { as: "p", variant: "callout", tone: "secondary", selectable: kind === "error", className: "max-w-form", children: message }) : null,
2383
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "mt-2 flex items-center gap-2", children: actions }) : null
2384
+ ]
2385
+ }
2386
+ );
2387
+ }
2388
+ var BANNER_TONE = {
2389
+ neutral: { box: "bg-fill", icon: "text-label-secondary" },
2390
+ info: { box: "bg-system-blue/10", icon: "text-system-blue" },
2391
+ warning: { box: "bg-system-orange/12", icon: "text-system-orange" },
2392
+ danger: { box: "bg-system-red/10", icon: "text-system-red" },
2393
+ success: { box: "bg-system-green/10", icon: "text-system-green" }
2394
+ };
2395
+ function Banner({ tone, icon, title, message, actions, className, ...props }) {
2396
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2397
+ "div",
2398
+ {
2399
+ role: tone === "danger" || tone === "warning" ? "alert" : "status",
2400
+ "data-slot": "banner",
2401
+ "data-tone": tone,
2402
+ className: cn("flex gap-2.5 rounded-group px-3 py-2", message ? "items-start" : "items-center", BANNER_TONE[tone].box, className),
2403
+ ...props,
2404
+ children: [
2405
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: cn("flex shrink-0 [&_svg]:size-icon", message && "mt-px", BANNER_TONE[tone].icon), children: icon }) : null,
2406
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
2407
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { emphasized: true, children: title }),
2408
+ message ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { as: "p", variant: "callout", tone: "secondary", selectable: true, children: message }) : null
2409
+ ] }),
2410
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex shrink-0 items-center gap-2", children: actions }) : null
2411
+ ]
2412
+ }
2413
+ );
2414
+ }
2415
+ function AlertGlyph() {
2416
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
2417
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
2418
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("path", { d: "M12 9v4" }),
2419
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("path", { d: "M12 17h.01" })
2420
+ ] });
2421
+ }
2422
+ function ErrorBanner({ error, onDismiss, title = "That didn't work", ...props }) {
2423
+ if (!error) return null;
2424
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2425
+ Banner,
2426
+ {
2427
+ tone: "danger",
2428
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AlertGlyph, {}),
2429
+ title,
2430
+ message: error.message,
2431
+ actions: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Button, { size: "sm", onClick: onDismiss, children: "Dismiss" }),
2432
+ ...props
2433
+ }
2434
+ );
2435
+ }
2436
+
2437
+ // src/desktop/resource.tsx
2438
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2439
+ function Resource({ state, loading, failed, isEmpty, empty, size = "inline", children }) {
2440
+ if (state.data === void 0) {
2441
+ if (state.error) {
2442
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2443
+ StateView,
2444
+ {
2445
+ kind: "error",
2446
+ size,
2447
+ title: failed,
2448
+ message: state.error.message,
2449
+ actions: state.refetch ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { onClick: () => void state.refetch?.(), children: "Try again" }) : void 0
2450
+ }
2451
+ );
2452
+ }
2453
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StateView, { kind: "loading", size, title: loading });
2454
+ }
2455
+ const blank = isEmpty ? isEmpty(state.data) : Array.isArray(state.data) && state.data.length === 0;
2456
+ if (blank && empty) return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: empty });
2457
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: children(state.data) });
2458
+ }
2459
+
2460
+ // src/desktop/tag.tsx
2461
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2462
+ var TONE = {
2463
+ neutral: "bg-fill-secondary text-label-secondary",
2464
+ tint: "bg-tint/12 text-tint",
2465
+ success: "bg-system-green/14 text-system-green",
2466
+ warning: "bg-system-orange/14 text-system-orange",
2467
+ danger: "bg-system-red/12 text-system-red"
2468
+ };
2469
+ function Tag({ tone = "neutral", className, ...props }) {
2470
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2471
+ "span",
2472
+ {
2473
+ "data-slot": "tag",
2474
+ "data-tone": tone,
2475
+ className: cn(
2476
+ "inline-flex h-4.5 shrink-0 items-center gap-1 whitespace-nowrap rounded-full px-1.5 text-caption font-medium [&_svg]:size-2.5",
2477
+ TONE[tone],
2478
+ className
2479
+ ),
2480
+ ...props
2481
+ }
2482
+ );
2483
+ }
2484
+ var DOT = {
2485
+ neutral: "bg-system-gray",
2486
+ success: "bg-system-green",
2487
+ warning: "bg-system-orange",
2488
+ danger: "bg-system-red",
2489
+ tint: "bg-tint"
2490
+ };
2491
+ function StatusLight({ tone, label, className, ...props }) {
2492
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2493
+ "span",
2494
+ {
2495
+ role: "img",
2496
+ "aria-label": label,
2497
+ "data-slot": "status-light",
2498
+ className: cn("inline-block size-2 shrink-0 rounded-full", DOT[tone], className),
2499
+ ...props
2500
+ }
2501
+ );
2502
+ }
2503
+ function Kbd({ className, ...props }) {
2504
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2505
+ "kbd",
2506
+ {
2507
+ "data-slot": "kbd",
2508
+ className: cn("inline-flex h-4.5 items-center rounded-control bg-fill-secondary px-1 font-sans text-caption text-label-secondary", className),
2509
+ ...props
2510
+ }
2511
+ );
2512
+ }
2513
+
2514
+ // src/desktop/coming-soon.tsx
2515
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2516
+ function ComingSoon({ icon, title, summary, includes, className, ...props }) {
2517
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Page, { width: "full", "data-coming-soon": title, className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "mx-auto flex max-w-form flex-col items-center gap-3 pt-16 text-center", children: [
2518
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "flex size-16 items-center justify-center rounded-panel bg-fill-secondary text-label-secondary [&_svg]:size-icon-xl", children: icon }),
2519
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col items-center gap-1.5", children: [
2520
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Tag, { children: "Coming soon" }),
2521
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { as: "h1", variant: "title-1", children: title }),
2522
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { as: "p", variant: "body", tone: "secondary", className: "max-w-form", children: summary })
2523
+ ] }),
2524
+ includes && includes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("ul", { className: "mt-3 flex flex-col gap-2 text-left", children: includes.slice(0, 4).map((line) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("li", { className: "flex items-start gap-2", children: [
2525
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: "mt-1.5 size-1.5 shrink-0 rounded-full bg-label-tertiary" }),
2526
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { variant: "callout", tone: "secondary", children: line })
2527
+ ] }, line)) }) : null
2528
+ ] }) });
2529
+ }
2530
+
2531
+ // src/desktop/meter.tsx
2532
+ var ProgressPrimitive = __toESM(require("@radix-ui/react-progress"), 1);
2533
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2534
+ var METER_THRESHOLDS = { warning: 0.7, critical: 0.9 };
2535
+ function meterTone(fraction) {
2536
+ if (fraction >= METER_THRESHOLDS.critical) return "critical";
2537
+ if (fraction >= METER_THRESHOLDS.warning) return "warning";
2538
+ return "normal";
2539
+ }
2540
+ function Meter({ value, max = 100, kind = "progress", size = "md", className, "aria-label": ariaLabel, ...data }) {
2541
+ const fraction = value === null ? 0 : Math.min(1, Math.max(0, value / max));
2542
+ const tone = kind === "level" ? meterTone(fraction) : "progress";
2543
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2544
+ ProgressPrimitive.Root,
2545
+ {
2546
+ ...data,
2547
+ value,
2548
+ max,
2549
+ "aria-label": ariaLabel,
2550
+ "data-slot": "meter",
2551
+ className: cn("relative w-full min-w-16 overflow-hidden rounded-full bg-fill-tertiary", size === "sm" ? "h-1" : "h-1.5", className),
2552
+ children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2553
+ ProgressPrimitive.Indicator,
2554
+ {
2555
+ className: cn(
2556
+ "h-full rounded-full transition-all duration-200",
2557
+ value === null && "w-1/3 animate-pulse",
2558
+ tone === "progress" && "bg-tint",
2559
+ tone === "normal" && "bg-system-green",
2560
+ tone === "warning" && "bg-system-orange",
2561
+ tone === "critical" && "bg-system-red"
2562
+ ),
2563
+ style: value === null ? void 0 : { width: `${fraction * 100}%` }
2564
+ }
2565
+ )
2566
+ }
2567
+ );
2568
+ }
2569
+
2570
+ // src/desktop/format.ts
2571
+ var BYTE_UNITS = ["bytes", "KB", "MB", "GB", "TB", "PB"];
2572
+ function formatBytes(bytes) {
2573
+ if (bytes === null || bytes === void 0 || !Number.isFinite(bytes)) return "\u2014";
2574
+ if (bytes < 1e3) return `${Math.round(bytes)} ${bytes === 1 ? "byte" : "bytes"}`;
2575
+ let value = bytes;
2576
+ let unit = 0;
2577
+ while (value >= 1e3 && unit < BYTE_UNITS.length - 1) {
2578
+ value /= 1e3;
2579
+ unit += 1;
2580
+ }
2581
+ return `${value >= 100 ? Math.round(value) : value.toFixed(1).replace(/\.0$/, "")} ${BYTE_UNITS[unit]}`;
2582
+ }
2583
+ function formatDuration(ms) {
2584
+ if (ms === null || ms === void 0 || !Number.isFinite(ms) || ms < 0) return "\u2014";
2585
+ const s = Math.floor(ms / 1e3);
2586
+ if (s < 60) return `${s} sec`;
2587
+ const m = Math.floor(s / 60);
2588
+ if (m < 60) return `${m} min`;
2589
+ const h = Math.floor(m / 60);
2590
+ if (h < 24) return m % 60 ? `${h} hr ${m % 60} min` : `${h} hr`;
2591
+ const d = Math.floor(h / 24);
2592
+ return h % 24 ? `${d} ${d === 1 ? "day" : "days"} ${h % 24} hr` : `${d} ${d === 1 ? "day" : "days"}`;
2593
+ }
2594
+ var RELATIVE = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
2595
+ var SAME_YEAR = new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
2596
+ var OTHER_YEAR = new Intl.DateTimeFormat(void 0, { year: "numeric", month: "short", day: "numeric" });
2597
+ function formatRelativeTime(at, now = Date.now()) {
2598
+ if (at === null || at === void 0) return "\u2014";
2599
+ const time = at instanceof Date ? at.getTime() : typeof at === "string" ? Date.parse(at) : at;
2600
+ if (!Number.isFinite(time)) return "\u2014";
2601
+ const seconds = Math.round((time - now) / 1e3);
2602
+ const abs = Math.abs(seconds);
2603
+ if (abs < 45) return "just now";
2604
+ if (abs < 3600) return RELATIVE.format(Math.round(seconds / 60), "minute");
2605
+ if (abs < 86400) return RELATIVE.format(Math.round(seconds / 3600), "hour");
2606
+ if (abs < 86400 * 2) return RELATIVE.format(Math.round(seconds / 86400), "day");
2607
+ return new Date(time).getFullYear() === new Date(now).getFullYear() ? SAME_YEAR.format(time) : OTHER_YEAR.format(time);
2608
+ }
2609
+ function errorMessage(error) {
2610
+ if (error instanceof Error) return error.message || error.name;
2611
+ if (typeof error === "string") return error;
2612
+ if (error && typeof error === "object" && "message" in error && typeof error.message === "string") {
2613
+ return error.message;
2614
+ }
2615
+ return "Something went wrong.";
2616
+ }
2617
+ function formatAge(at, now = Date.now()) {
2618
+ if (at === null || at === void 0) return "\u2014";
2619
+ const time = at instanceof Date ? at.getTime() : typeof at === "string" ? Date.parse(at) : at;
2620
+ if (!Number.isFinite(time)) return "\u2014";
2621
+ const minutes = Math.floor((now - time) / 6e4);
2622
+ if (minutes < 1) return "now";
2623
+ if (minutes < 60) return `${minutes}m`;
2624
+ if (minutes < 60 * 24) return `${Math.floor(minutes / 60)}h`;
2625
+ if (minutes < 60 * 24 * 7) return `${Math.floor(minutes / (60 * 24))}d`;
2626
+ return new Date(time).toLocaleDateString(void 0, { month: "short", day: "numeric" });
2627
+ }
2628
+ var CLOCK = new Intl.DateTimeFormat(void 0, { hour: "numeric", minute: "2-digit" });
2629
+ function formatClockTime(at) {
2630
+ if (at === null || at === void 0) return "\u2014";
2631
+ const time = at instanceof Date ? at.getTime() : typeof at === "string" ? Date.parse(at) : at;
2632
+ return Number.isFinite(time) ? CLOCK.format(time) : "\u2014";
2633
+ }
2634
+ function formatUsage(used, total) {
2635
+ if (used === null || used === void 0 || total === null || total === void 0) return "\u2014";
2636
+ return `${formatBytes(used)} of ${formatBytes(total)} in use`;
2637
+ }
2638
+
2639
+ // src/context-menu.tsx
2640
+ var ContextMenuPrimitive = __toESM(require("@radix-ui/react-context-menu"), 1);
2641
+ var React20 = __toESM(require("react"), 1);
2642
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2643
+ var ContextMenu = ContextMenuPrimitive.Root;
2644
+ var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
2645
+ var SURFACE_CLASS2 = "z-[10001] min-w-[8rem] max-h-[var(--radix-context-menu-content-available-height)] overflow-y-auto overflow-x-hidden overscroll-contain rounded-md border bg-popover p-1 text-popover-foreground";
2646
+ var ITEM_CLASS = "relative flex select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:opacity-50";
2647
+ var INDICATOR_ITEM_CLASS = "relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:opacity-50";
2648
+ var ContextMenuSubTrigger = React20.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2649
+ ContextMenuPrimitive.SubTrigger,
2650
+ {
2651
+ ref,
2652
+ "data-slot": "context-menu-sub-trigger",
2653
+ className: cn2(
2654
+ "flex select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
2655
+ inset && "pl-8",
2656
+ className
2657
+ ),
2658
+ ...props,
2659
+ children: [
2660
+ children,
2661
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RadixChevronRightIcon, { className: "ml-auto h-4 w-4" })
2662
+ ]
2663
+ }
2664
+ ));
2665
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
2666
+ var ContextMenuSubContent = React20.forwardRef(({ className, container, onFocusOutside, children, ...props }, ref) => {
2667
+ const portalContainer = usePortalContainer(container);
2668
+ const keep = useSubmenuSurvivesParentPanelFocus(ref, onFocusOutside);
2669
+ const edges = useMenuScrollEdges(keep.ref);
2670
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2671
+ ContextMenuPrimitive.SubContent,
2672
+ {
2673
+ ref: edges.ref,
2674
+ onFocusOutside: keep.onFocusOutside,
2675
+ "data-slot": "context-menu-sub-content",
2676
+ className: cn2(SURFACE_CLASS2, edges.surfaceClassName, "shadow-lg", MOTION_POPPER, className),
2677
+ ...props,
2678
+ children: edges.wrap(children)
2679
+ }
2680
+ ) });
2681
+ });
2682
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
2683
+ var ContextMenuContent = React20.forwardRef(({ className, container, children, ...props }, ref) => {
2684
+ const portalContainer = usePortalContainer(container);
2685
+ const edges = useMenuScrollEdges(ref);
2686
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2687
+ ContextMenuPrimitive.Content,
2688
+ {
2689
+ ref: edges.ref,
2690
+ "data-slot": "context-menu-content",
2691
+ className: cn2(SURFACE_CLASS2, edges.surfaceClassName, "shadow-md", MOTION_POPPER, className),
2692
+ ...props,
2693
+ children: edges.wrap(children)
2694
+ }
2695
+ ) });
2696
+ });
2697
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
2698
+ var ContextMenuItem = React20.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2699
+ ContextMenuPrimitive.Item,
2700
+ {
2701
+ ref,
2702
+ "data-slot": "context-menu-item",
2703
+ className: cn2(
2704
+ ITEM_CLASS,
2705
+ "gap-2 [&>svg]:size-4 [&>svg]:shrink-0",
2706
+ inset && "pl-8",
2707
+ className
2708
+ ),
2709
+ ...props
2710
+ }
2711
+ ));
2712
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
2713
+ var ContextMenuCheckboxItem = React20.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2714
+ ContextMenuPrimitive.CheckboxItem,
2715
+ {
2716
+ ref,
2717
+ "data-slot": "context-menu-checkbox-item",
2718
+ className: cn2(INDICATOR_ITEM_CLASS, className),
2719
+ ...props,
2720
+ children: [
2721
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CheckIcon, { className: "h-4 w-4" }) }) }),
2722
+ children
2723
+ ]
2724
+ }
2725
+ ));
2726
+ ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
2727
+ var ContextMenuRadioItem = React20.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2728
+ ContextMenuPrimitive.RadioItem,
2729
+ {
2730
+ ref,
2731
+ "data-slot": "context-menu-radio-item",
2732
+ className: cn2(INDICATOR_ITEM_CLASS, className),
2733
+ ...props,
2734
+ children: [
2735
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(DotFilledIcon, { className: "h-4 w-4 fill-current" }) }) }),
2736
+ children
2737
+ ]
2738
+ }
2739
+ ));
2740
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
2741
+ var ContextMenuLabel = React20.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2742
+ ContextMenuPrimitive.Label,
2743
+ {
2744
+ ref,
2745
+ "data-slot": "context-menu-label",
2746
+ className: cn2(
2747
+ "px-2 py-1.5 text-sm font-semibold text-foreground",
2748
+ inset && "pl-8",
2749
+ className
2750
+ ),
2751
+ ...props
2752
+ }
2753
+ ));
2754
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
2755
+ var ContextMenuSeparator = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2756
+ ContextMenuPrimitive.Separator,
2757
+ {
2758
+ ref,
2759
+ "data-slot": "context-menu-separator",
2760
+ className: cn2("-mx-1 my-1 h-px bg-border", className),
2761
+ ...props
2762
+ }
2763
+ ));
2764
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
2765
+ var ContextMenuShortcut = ({
2766
+ className,
2767
+ ...props
2768
+ }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2769
+ "span",
2770
+ {
2771
+ "data-slot": "context-menu-shortcut",
2772
+ className: cn2("ml-auto text-xs tracking-widest text-muted-foreground", className),
2773
+ ...props
2774
+ }
2775
+ );
2776
+ ContextMenuShortcut.displayName = "ContextMenuShortcut";
2777
+
2778
+ // src/dialog.tsx
2779
+ var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
2780
+ var VisuallyHidden = __toESM(require("@radix-ui/react-visually-hidden"), 1);
2781
+ var import_react_tree2 = require("@ai-matrx/kit/react-tree");
2782
+ var React22 = __toESM(require("react"), 1);
2783
+
2784
+ // src/radix-dialog-modal-context.tsx
2785
+ var React21 = __toESM(require("react"), 1);
2786
+ var import_jsx_runtime30 = require("react/jsx-runtime");
2787
+ var CONTEXT_SLOT2 = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.dialog-modal-context");
2788
+ var contextRegistry2 = globalThis;
2789
+ var RadixDialogModalContext = contextRegistry2[CONTEXT_SLOT2] ??= React21.createContext(true);
2790
+ function RadixDialogModalProvider({
2791
+ children,
2792
+ modal
2793
+ }) {
2794
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RadixDialogModalContext.Provider, { value: modal, children });
2795
+ }
2796
+ function useRadixDialogModal() {
2797
+ return React21.useContext(RadixDialogModalContext);
2798
+ }
2799
+
2800
+ // src/use-is-mobile.ts
2801
+ var import_media_query = require("@ai-matrx/kit/media-query");
2802
+
2803
+ // src/layer-front.ts
2804
+ var LAYER_FRONT_EVENT = "matrx:layer-front";
2805
+ function announceLayerFront(element) {
2806
+ if (typeof document === "undefined") return;
2807
+ document.dispatchEvent(
2808
+ new CustomEvent(LAYER_FRONT_EVENT, { detail: { element } })
2809
+ );
2810
+ }
2811
+
2812
+ // src/dialog.tsx
2813
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2814
+ var DialogWindowedByDefaultContext = React22.createContext(false);
2815
+ var Dialog = ({
2816
+ children,
2817
+ ...props
2818
+ }) => {
2819
+ const isMobile = (0, import_media_query.useIsMobile)();
2820
+ const modal = props.modal ?? isMobile;
2821
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(DialogWindowedByDefaultContext.Provider, { value: props.modal === void 0, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(DialogPrimitive.Root, { ...props, modal, children }) }) });
2822
+ };
2823
+ Dialog.displayName = "Dialog";
2824
+ var DialogTrigger = DialogPrimitive.Trigger;
2825
+ var DialogClose = DialogPrimitive.Close;
2826
+ var DialogPortal = ({
2827
+ container,
2828
+ ...props
2829
+ }) => {
2830
+ const resolved = usePortalContainer(container);
2831
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(DialogPrimitive.Portal, { container: resolved ?? null, ...props });
2832
+ };
2833
+ DialogPortal.displayName = "DialogPortal";
2834
+ var CONTEXT_SLOT3 = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.dialog-container-context");
2835
+ var contextRegistry3 = globalThis;
2836
+ var DialogContainerContext = contextRegistry3[CONTEXT_SLOT3] ??= React22.createContext(null);
2837
+ var DialogOverlay = React22.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2838
+ DialogPrimitive.Overlay,
2839
+ {
2840
+ ref,
2841
+ "data-slot": "dialog-overlay",
2842
+ className: cn2(
2843
+ // Page context behind the modal stays readable; separation comes from a
2844
+ // light token scrim, not a blur.
2845
+ "fixed inset-0 z-[10000] bg-[var(--matrx-overlay-scrim-soft)]",
2846
+ MOTION_OVERLAY,
2847
+ className
2848
+ ),
2849
+ ...props
2850
+ }
2851
+ ));
2852
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
2853
+ var DialogContentPrimitive = React22.forwardRef(({ onInteractOutside, ...props }, ref) => {
2854
+ const isModal = useRadixDialogModal();
2855
+ useModalLayer(isModal);
2856
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2857
+ DialogPrimitive.Content,
2858
+ {
2859
+ ...props,
2860
+ ref,
2861
+ "aria-modal": isModal || void 0,
2862
+ onInteractOutside: keepFloatingLayersInside(onInteractOutside)
2863
+ }
2864
+ );
2865
+ });
2866
+ DialogContentPrimitive.displayName = "DialogContentPrimitive";
2867
+ var DIALOG_DESKTOP_CLASSES = "matrx-dialog-card fixed inset-0 z-[10000] m-auto grid h-fit min-w-0 w-full max-w-lg gap-4 max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip border bg-background p-6 shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full sm:rounded-lg";
2868
+ var DIALOG_MOBILE_SHEET_CLASSES = "matrx-mobile-sheet matrx-dialog-card fixed inset-x-0 bottom-0 left-0 right-0 top-auto z-[10000] flex min-w-0 flex-col w-full max-w-full max-h-[90dvh] gap-4 [--dialog-pad:1rem] overflow-x-clip border-t bg-background p-4 pb-safe shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full rounded-t-2xl rounded-b-none overflow-y-auto overscroll-contain";
2869
+ var DIALOG_MOBILE_SHEET_OVERRIDE = "inset-x-0 bottom-0 left-0 right-0 top-auto translate-none w-full max-w-full max-h-[90dvh] rounded-b-none rounded-t-2xl overflow-y-auto";
2870
+ var DialogWindowHandleContext = React22.createContext(null);
2871
+ var WINDOW_KEEP_VISIBLE = 80;
2872
+ function isInteractiveTarget(target) {
2873
+ return target instanceof Element && Boolean(target.closest("button, a, input, textarea, select, [role='button'], [contenteditable='true']"));
2874
+ }
2875
+ var DialogContent = React22.forwardRef(
2876
+ ({
2877
+ className,
2878
+ children,
2879
+ mobileSheet = true,
2880
+ animated = true,
2881
+ showCloseButton = true,
2882
+ container,
2883
+ dismissOnOutsideClick = false,
2884
+ onInteractOutside,
2885
+ onEscapeKeyDown,
2886
+ onPointerDownCapture,
2887
+ onFocusCapture,
2888
+ style,
2889
+ ...props
2890
+ }, ref) => {
2891
+ const isMobile = (0, import_media_query.useIsMobile)();
2892
+ const isModal = useRadixDialogModal();
2893
+ const injectedContainer = usePortalContainer(container);
2894
+ const asSheet = mobileSheet && isMobile;
2895
+ const windowed = !isModal && !asSheet;
2896
+ const windowedByDefault = React22.useContext(DialogWindowedByDefaultContext);
2897
+ const [containerEl, setContainerEl] = React22.useState(
2898
+ null
2899
+ );
2900
+ const stacks = windowed && windowedByDefault;
2901
+ const [behind, setBehind] = React22.useState(false);
2902
+ React22.useEffect(() => {
2903
+ if (!stacks || !containerEl) return;
2904
+ const onFront = (event) => {
2905
+ const element = event.detail?.element ?? null;
2906
+ if (element && (element === containerEl || containerEl.contains(element))) return;
2907
+ setBehind(true);
2908
+ };
2909
+ document.addEventListener(LAYER_FRONT_EVENT, onFront);
2910
+ announceLayerFront(containerEl);
2911
+ return () => document.removeEventListener(LAYER_FRONT_EVENT, onFront);
2912
+ }, [stacks, containerEl]);
2913
+ const bringToFront = () => {
2914
+ if (!stacks || !containerEl) return;
2915
+ setBehind(false);
2916
+ announceLayerFront(containerEl);
2917
+ };
2918
+ const [offset, setOffset] = React22.useState({ x: 0, y: 0 });
2919
+ const dragRef = React22.useRef(null);
2920
+ const handle = React22.useMemo(() => {
2921
+ if (!windowed) return null;
2922
+ const clamp = (value, limit) => Math.max(-limit, Math.min(limit, value));
2923
+ return {
2924
+ onPointerDown: (event) => {
2925
+ if (event.button !== 0 || isInteractiveTarget(event.target)) return;
2926
+ dragRef.current = { x: event.clientX, y: event.clientY, baseX: offset.x, baseY: offset.y };
2927
+ event.currentTarget.setPointerCapture?.(event.pointerId);
2928
+ },
2929
+ onPointerMove: (event) => {
2930
+ const start = dragRef.current;
2931
+ if (!start) return;
2932
+ setOffset({
2933
+ x: clamp(start.baseX + event.clientX - start.x, window.innerWidth / 2 - WINDOW_KEEP_VISIBLE / 2),
2934
+ y: clamp(start.baseY + event.clientY - start.y, window.innerHeight / 2 - WINDOW_KEEP_VISIBLE / 2)
2935
+ });
2936
+ },
2937
+ onPointerUp: (event) => {
2938
+ if (!dragRef.current) return;
2939
+ dragRef.current = null;
2940
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
2941
+ },
2942
+ onPointerCancel: () => {
2943
+ dragRef.current = null;
2944
+ },
2945
+ onDoubleClick: () => setOffset({ x: 0, y: 0 })
2946
+ };
2947
+ }, [windowed, offset.x, offset.y]);
2948
+ const mergedRef = React22.useCallback(
2949
+ (node) => {
2950
+ setContainerEl(node);
2951
+ if (typeof ref === "function") ref(node);
2952
+ else if (ref)
2953
+ ref.current = node;
2954
+ },
2955
+ [ref]
2956
+ );
2957
+ const hasTitle = (0, import_react_tree2.treeContainsComponent)(children, DialogTitle) || (0, import_react_tree2.treeContainsComponent)(children, DialogPrimitive.Title);
2958
+ const hasDescription = (0, import_react_tree2.treeContainsComponent)(children, DialogDescription) || (0, import_react_tree2.treeContainsComponent)(children, DialogPrimitive.Description);
2959
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(DialogPortal, { container, children: [
2960
+ isModal ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(DialogOverlay, {}) : null,
2961
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
2962
+ DialogContentPrimitive,
2963
+ {
2964
+ ref: mergedRef,
2965
+ "data-slot": "dialog-content",
2966
+ className: cn2(
2967
+ asSheet ? DIALOG_MOBILE_SHEET_CLASSES : DIALOG_DESKTOP_CLASSES,
2968
+ animated && (asSheet ? MOTION_BOTTOM_SHEET : MOTION_DIALOG),
2969
+ className,
2970
+ asSheet && DIALOG_MOBILE_SHEET_OVERRIDE,
2971
+ // A non-modal dialog is the coexistence contract for content that
2972
+ // can sit beside a host's floating window manager (which starts at
2973
+ // z=1000); staying below that boundary makes a newly focused window
2974
+ // usable without coupling the two systems.
2975
+ !isModal && !windowedByDefault && "z-[900]",
2976
+ // Another layer came to the front after this window (layer-front.ts).
2977
+ stacks && behind && "z-[999]",
2978
+ // Without an overlay the card needs its own separation from the page.
2979
+ windowed && "shadow-2xl ring-1 ring-border/60"
2980
+ ),
2981
+ style: windowed && (offset.x !== 0 || offset.y !== 0) ? { ...style, translate: `${offset.x}px ${offset.y}px` } : style,
2982
+ onPointerDownCapture: (event) => {
2983
+ onPointerDownCapture?.(event);
2984
+ if (behind) bringToFront();
2985
+ },
2986
+ onFocusCapture: (event) => {
2987
+ onFocusCapture?.(event);
2988
+ if (behind) bringToFront();
2989
+ },
2990
+ onInteractOutside: (event) => {
2991
+ onInteractOutside?.(event);
2992
+ if (windowed && !dismissOnOutsideClick) event.preventDefault();
2993
+ },
2994
+ onEscapeKeyDown: (event) => {
2995
+ onEscapeKeyDown?.(event);
2996
+ const pressedIn = event.target instanceof Node && event.target !== document.body ? event.target : document.activeElement;
2997
+ if (windowed && containerEl && !(pressedIn && containerEl.contains(pressedIn))) {
2998
+ event.preventDefault();
2999
+ }
3000
+ },
3001
+ ...hasDescription ? {} : { "aria-describedby": void 0 },
3002
+ ...props,
3003
+ children: [
3004
+ hasTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(VisuallyHidden.Root, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(DialogPrimitive.Title, { children: "Dialog" }) }),
3005
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(DialogWindowHandleContext.Provider, { value: handle, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3006
+ PortalContainerProvider,
3007
+ {
3008
+ container: containerEl ?? injectedContainer ?? null,
3009
+ children
3010
+ }
3011
+ ) }) }),
3012
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
3013
+ DialogPrimitive.Close,
3014
+ {
3015
+ "data-slot": "dialog-close",
3016
+ "aria-label": "Close",
3017
+ className: "absolute right-2 top-4 flex h-11 w-11 items-center justify-center rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 data-[state=open]:bg-accent data-[state=open]:text-muted-foreground sm:right-4 lg:h-10 lg:w-10",
3018
+ children: [
3019
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(XIcon, { className: "h-4 w-4" }),
3020
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "sr-only", children: "Close" })
3021
+ ]
3022
+ }
3023
+ ) : null
3024
+ ]
3025
+ }
3026
+ )
3027
+ ] });
3028
+ }
3029
+ );
3030
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
3031
+ var DialogHeader = ({
3032
+ className,
3033
+ ...props
3034
+ }) => {
3035
+ const handle = React22.useContext(DialogWindowHandleContext);
3036
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3037
+ "div",
3038
+ {
3039
+ "data-slot": "dialog-header",
3040
+ ...handle ? {
3041
+ ...handle,
3042
+ "data-window-handle": "",
3043
+ title: "Drag to move \xB7 double-click to recenter"
3044
+ } : {},
3045
+ className: cn2(
3046
+ // DialogContent owns an absolute close control. Reserve its hit area in
3047
+ // every header so trailing actions never render underneath it.
3048
+ "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
3049
+ handle && "cursor-grab select-none active:cursor-grabbing",
3050
+ className
3051
+ ),
3052
+ ...props
3053
+ }
3054
+ );
3055
+ };
3056
+ DialogHeader.displayName = "DialogHeader";
3057
+ var DialogFooter = ({
3058
+ className,
3059
+ ...props
3060
+ }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3061
+ "div",
3062
+ {
3063
+ "data-slot": "dialog-footer",
3064
+ className: cn2(
3065
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
3066
+ // Ruling 3/4 — sticky to the card edges so a scrolled body never shows
3067
+ // through under the actions, and safe-area padded on a phone.
3068
+ //
3069
+ // 🚨 THERE IS NO `mb-[…]` HERE, AND THERE MUST NEVER BE ONE AGAIN
3070
+ // (0.11.3, feedback bf8fb00b). The bleed over the card's bottom padding
3071
+ // used to be a NEGATIVE BLOCK MARGIN, which makes this box taller than
3072
+ // the grid area the card allocates it — and `position: sticky` CLAMPS a
3073
+ // box to its containing block, so the browser yanked the footer UP by
3074
+ // `--dialog-pad` against the card's `gap-4` and painted 8px of opaque
3075
+ // footer over the last line of the consequence, at every length. The
3076
+ // card now RESERVES this footer's block size instead (`matrx-dialog-card`
3077
+ // in styles.css hands over its `padding-bottom`), so the bleed costs no
3078
+ // margin at all. Guard: `sticky-footer-geometry.test.tsx`.
3079
+ //
3080
+ // These stay UTILITIES rather than a shipped rule so a caller's
3081
+ // `className` still wins through tailwind-merge — a shipped rule would
3082
+ // have to be unlayered to survive Tailwind preflight (§ THE PREFLIGHT
3083
+ // RULE in styles.css) and would then override every caller's padding.
3084
+ "sticky bottom-0 z-10 bg-background pt-3",
3085
+ "mx-[calc(var(--dialog-pad,0px)*-1)] px-[var(--dialog-pad,0px)] pb-[var(--dialog-pad,0px)]",
3086
+ className
3087
+ ),
3088
+ ...props
3089
+ }
3090
+ );
3091
+ DialogFooter.displayName = "DialogFooter";
3092
+ var DialogTitle = React22.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3093
+ DialogPrimitive.Title,
3094
+ {
3095
+ ref,
3096
+ "data-slot": "dialog-title",
3097
+ className: cn2("text-lg font-semibold leading-none tracking-tight", className),
3098
+ ...props
3099
+ }
3100
+ ));
3101
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
3102
+ var DialogDescription = React22.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3103
+ DialogPrimitive.Description,
3104
+ {
3105
+ ref,
3106
+ "data-slot": "dialog-description",
3107
+ className: cn2("text-sm text-muted-foreground", className),
3108
+ ...props
3109
+ }
3110
+ ));
3111
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
3112
+
3113
+ // src/confirm-host.tsx
3114
+ var import_confirm_opener = require("@ai-matrx/kit/confirm-opener");
3115
+ var import_opener_react = require("@ai-matrx/kit/opener-react");
3116
+ var React23 = __toESM(require("react"), 1);
3117
+ var import_jsx_runtime32 = require("react/jsx-runtime");
3118
+ function ConfirmDialogHost() {
3119
+ const { shown, open, settle } = (0, import_opener_react.useOpenerHost)(import_confirm_opener.confirmOpener);
3120
+ const [readyFor, setReadyFor] = React23.useState(null);
3121
+ const ready = shown?.ready;
3122
+ React23.useEffect(() => {
3123
+ if (!shown || !ready) return void 0;
3124
+ let live = true;
3125
+ const release = () => {
3126
+ if (live) setReadyFor(shown);
3127
+ };
3128
+ Promise.resolve(ready).then(release, release);
3129
+ return () => {
3130
+ live = false;
3131
+ };
3132
+ }, [shown, ready]);
3133
+ const held = !!ready && readyFor !== shown;
3134
+ const handleConfirm = React23.useCallback(() => settle(true), [settle]);
3135
+ const handleOpenChange = React23.useCallback(
3136
+ (next) => {
3137
+ if (!next) settle(false);
3138
+ },
3139
+ [settle]
3140
+ );
3141
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3142
+ ConfirmDialog,
3143
+ {
3144
+ open,
3145
+ onOpenChange: handleOpenChange,
3146
+ title: shown?.title ?? "",
3147
+ description: shown?.description,
3148
+ confirmLabel: shown?.confirmLabel,
3149
+ cancelLabel: shown?.cancelLabel,
3150
+ variant: shown?.variant,
3151
+ confirmHeld: held,
3152
+ onConfirm: handleConfirm
3153
+ }
3154
+ );
3155
+ }
3156
+
3157
+ // src/popover.tsx
3158
+ var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
3159
+ var React24 = __toESM(require("react"), 1);
3160
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3161
+ var Popover = PopoverPrimitive.Root;
3162
+ var PopoverTrigger = PopoverPrimitive.Trigger;
3163
+ var PopoverAnchor = PopoverPrimitive.Anchor;
3164
+ var PopoverContent = React24.forwardRef(
3165
+ ({
3166
+ className,
3167
+ align = "center",
3168
+ sideOffset = 4,
3169
+ container,
3170
+ animated = true,
3171
+ sizing = "fixed",
3172
+ collisionPadding = 16,
3173
+ ...props
3174
+ }, ref) => {
3175
+ const portalContainer = usePortalContainer(container);
3176
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3177
+ PopoverPrimitive.Content,
3178
+ {
3179
+ ref,
3180
+ align,
3181
+ sideOffset,
3182
+ collisionPadding,
3183
+ className: cn2(
3184
+ // Cap to the viewport space Radix measured and scroll — a popover taller
3185
+ // than the screen must never trap the user with unreachable content.
3186
+ // z must EQUAL the dialog layer (z-[10000]), never exceed it: with equal
3187
+ // z, DOM portal order decides, so a dialog opened FROM a popover stacks
3188
+ // above it, and a popover opened from a dialog still stacks above the
3189
+ // dialog. z-[10001] buried dialogs behind fullscreen popovers.
3190
+ "z-[10000] max-h-[var(--radix-popover-content-available-height)] overflow-y-auto overscroll-contain rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
3191
+ sizing === "content" ? "w-auto min-w-[min(max(var(--radix-popover-trigger-width),20rem),calc(100vw-2rem))] max-w-[min(28rem,calc(100vw-2rem))]" : "w-72 max-w-[calc(100vw-2rem)]",
3192
+ animated && MOTION_POPPER,
3193
+ className
3194
+ ),
3195
+ ...props
3196
+ }
3197
+ ) });
3198
+ }
3199
+ );
3200
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
3201
+
3202
+ // src/collapsible.tsx
3203
+ var CollapsiblePrimitive = __toESM(require("@radix-ui/react-collapsible"), 1);
3204
+ var React25 = __toESM(require("react"), 1);
3205
+ var import_jsx_runtime34 = require("react/jsx-runtime");
3206
+ var Collapsible = CollapsiblePrimitive.Root;
3207
+ var CollapsibleTrigger2 = CollapsiblePrimitive.CollapsibleTrigger;
3208
+ var CollapsibleContent2 = React25.forwardRef(({ className, animated = true, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3209
+ CollapsiblePrimitive.CollapsibleContent,
3210
+ {
3211
+ ref,
3212
+ "data-slot": "collapsible-content",
3213
+ className: cn2(
3214
+ animated && "matrx-collapsible-content overflow-hidden",
3215
+ className
3216
+ ),
3217
+ ...props
3218
+ }
3219
+ ));
3220
+ CollapsibleContent2.displayName = "CollapsibleContent";
3221
+
3222
+ // src/skeleton.tsx
3223
+ var import_jsx_runtime35 = require("react/jsx-runtime");
3224
+ function Skeleton({ className, animated = true, ...props }) {
3225
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3226
+ "div",
3227
+ {
3228
+ "data-slot": "skeleton",
3229
+ className: cn2(
3230
+ "rounded-md bg-primary/10",
3231
+ animated && MOTION_PULSE,
3232
+ className
3233
+ ),
3234
+ ...props
3235
+ }
3236
+ );
3237
+ }
3238
+
3239
+ // src/app-shell/app-rail.tsx
3240
+ var React26 = __toESM(require("react"), 1);
3241
+
3242
+ // src/app-shell/status-dot.tsx
3243
+ var import_jsx_runtime36 = require("react/jsx-runtime");
3244
+ var FILL = {
3245
+ info: "bg-info",
3246
+ warning: "bg-warning",
3247
+ danger: "bg-destructive",
3248
+ success: "bg-success",
3249
+ neutral: "bg-muted-foreground/60"
3250
+ };
3251
+ var RING = {
3252
+ info: "border-info",
3253
+ warning: "border-warning",
3254
+ danger: "border-destructive",
3255
+ success: "border-success",
3256
+ neutral: "border-muted-foreground/60"
3257
+ };
3258
+ function StatusDot({ tone, variant = "solid", label, className, ...props }) {
3259
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3260
+ "span",
3261
+ {
3262
+ "data-slot": "status-dot",
3263
+ "data-tone": tone,
3264
+ "data-variant": variant,
3265
+ ...label ? { role: "img", "aria-label": label } : { "aria-hidden": true },
3266
+ className: cn2(
3267
+ "inline-block shrink-0 rounded-full",
3268
+ variant === "solid" ? cn2("size-1.5", FILL[tone]) : cn2("size-2 border-[1.5px] bg-transparent", RING[tone]),
3269
+ className
3270
+ ),
3271
+ ...props
3272
+ }
3273
+ );
3274
+ }
3275
+
3276
+ // src/app-shell/app-rail.tsx
3277
+ var import_jsx_runtime37 = require("react/jsx-runtime");
3278
+ function AppRail({ className, style, ...props }) {
3279
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3280
+ "nav",
3281
+ {
3282
+ "data-slot": "app-rail",
3283
+ "aria-label": "Areas",
3284
+ className: cn2("flex h-full w-(--app-rail-width) shrink-0 flex-col items-center gap-1 py-2", className),
3285
+ style: { "--app-rail-width": "48px", ...style },
3286
+ ...props
3287
+ }
3288
+ );
3289
+ }
3290
+ function AppRailGroup({ className, ...props }) {
3291
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { "data-slot": "app-rail-group", className: cn2("flex flex-col items-center gap-1", className), ...props });
3292
+ }
3293
+ function AppRailSpacer() {
3294
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { "data-slot": "app-rail-spacer", className: "flex-1" });
3295
+ }
3296
+ var AppRailItem = React26.forwardRef(function AppRailItem2({ icon, label, shortcut, active = false, attention, attentionLabel, className, ...props }, ref) {
3297
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(Tooltip, { children: [
3298
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
3299
+ "button",
3300
+ {
3301
+ ref,
3302
+ type: "button",
3303
+ "data-slot": "app-rail-item",
3304
+ "data-active": active,
3305
+ "aria-label": label,
3306
+ "aria-current": active ? "page" : void 0,
3307
+ className: cn2(
3308
+ "relative flex size-8 items-center justify-center rounded-lg text-foreground/55 outline-none transition-colors",
3309
+ "hover:bg-foreground/[0.06] hover:text-foreground",
3310
+ "data-[active=true]:bg-foreground/[0.08] data-[active=true]:text-foreground",
3311
+ "focus-visible:ring-2 focus-visible:ring-ring",
3312
+ "[&_svg]:size-[18px] [&_svg]:shrink-0",
3313
+ className
3314
+ ),
3315
+ ...props,
3316
+ children: [
3317
+ icon,
3318
+ attention ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3319
+ StatusDot,
3320
+ {
3321
+ tone: attention,
3322
+ variant: "ring",
3323
+ ...attentionLabel ? { label: attentionLabel } : {},
3324
+ className: "absolute right-0.5 bottom-0.5"
3325
+ }
3326
+ ) : null
3327
+ ]
3328
+ }
3329
+ ) }),
3330
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipContent, { side: "right", align: "center", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "flex items-center gap-2", children: [
3331
+ label,
3332
+ shortcut ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "opacity-60", children: shortcut }) : null
3333
+ ] }) })
3334
+ ] });
3335
+ });
3336
+ var AppRailAvatar = React26.forwardRef(function AppRailAvatar2({ initials = "", label, className, children, ...props }, ref) {
3337
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(Tooltip, { children: [
3338
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3339
+ "button",
3340
+ {
3341
+ ref,
3342
+ type: "button",
3343
+ "data-slot": "app-rail-avatar",
3344
+ "aria-label": label,
3345
+ className: cn2(
3346
+ "flex size-6 items-center justify-center rounded-full bg-foreground/[0.12] text-[10px] font-semibold leading-none text-foreground/80 outline-none [&_svg]:size-3.5",
3347
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
3348
+ className
3349
+ ),
3350
+ ...props,
3351
+ children: children ?? initials.slice(0, 2).toUpperCase()
3352
+ }
3353
+ ) }),
3354
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipContent, { side: "right", align: "center", children: label })
3355
+ ] });
3356
+ });
3357
+
3358
+ // src/app-shell/canvas.tsx
3359
+ var React27 = __toESM(require("react"), 1);
3360
+
3361
+ // src/resizable.tsx
3362
+ var import_react_resizable_panels = require("react-resizable-panels");
3363
+ var import_jsx_runtime38 = require("react/jsx-runtime");
3364
+ var HANDLE_SIZES = {
3365
+ xs: "w-0.5 [&[aria-orientation=horizontal]]:h-0.5 [&[aria-orientation=horizontal]]:w-full",
3366
+ sm: "w-1 [&[aria-orientation=horizontal]]:h-1 [&[aria-orientation=horizontal]]:w-full",
3367
+ md: "w-1.5 [&[aria-orientation=horizontal]]:h-1.5 [&[aria-orientation=horizontal]]:w-full",
3368
+ lg: "w-2 [&[aria-orientation=horizontal]]:h-2 [&[aria-orientation=horizontal]]:w-full",
3369
+ xl: "w-3 [&[aria-orientation=horizontal]]:h-3 [&[aria-orientation=horizontal]]:w-full",
3370
+ "2xl": "w-4 [&[aria-orientation=horizontal]]:h-4 [&[aria-orientation=horizontal]]:w-full",
3371
+ "3xl": "w-6 [&[aria-orientation=horizontal]]:h-6 [&[aria-orientation=horizontal]]:w-full",
3372
+ "4xl": "w-8 [&[aria-orientation=horizontal]]:h-8 [&[aria-orientation=horizontal]]:w-full"
3373
+ };
3374
+ var ResizablePanelGroup = ({
3375
+ className,
3376
+ ...props
3377
+ }) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3378
+ import_react_resizable_panels.Group,
3379
+ {
3380
+ "data-slot": "resizable-group",
3381
+ className: cn2("flex h-full w-full", className),
3382
+ ...props
3383
+ }
3384
+ );
3385
+ ResizablePanelGroup.displayName = "ResizablePanelGroup";
3386
+ var ResizablePanel = import_react_resizable_panels.Panel;
3387
+ var ResizableHandle = ({
3388
+ withHandle,
3389
+ size = "xs",
3390
+ className,
3391
+ ...props
3392
+ }) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3393
+ import_react_resizable_panels.Separator,
3394
+ {
3395
+ "data-slot": "resizable-handle",
3396
+ className: cn2(
3397
+ "group/handle relative flex shrink-0 items-center justify-center bg-border transition-colors",
3398
+ // Invisible hit target centered on the line; wider still on touch.
3399
+ "after:absolute after:inset-y-0 after:left-1/2 after:w-1.5 after:-translate-x-1/2 after:content-['']",
3400
+ "pointer-coarse:after:w-11",
3401
+ "[&[aria-orientation=horizontal]]:after:inset-x-0 [&[aria-orientation=horizontal]]:after:left-0 [&[aria-orientation=horizontal]]:after:top-1/2 [&[aria-orientation=horizontal]]:after:h-1.5 [&[aria-orientation=horizontal]]:after:w-full [&[aria-orientation=horizontal]]:after:-translate-x-0 [&[aria-orientation=horizontal]]:after:-translate-y-1/2",
3402
+ "pointer-coarse:[&[aria-orientation=horizontal]]:after:h-11",
3403
+ // The drag-outline bug: suppress for ALL focus, restore for keyboard.
3404
+ "focus:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1",
3405
+ // Library-driven state feedback.
3406
+ "data-[separator=hover]:bg-primary data-[separator=active]:bg-primary",
3407
+ HANDLE_SIZES[size],
3408
+ "cursor-col-resize [&[aria-orientation=horizontal]]:cursor-row-resize",
3409
+ className
3410
+ ),
3411
+ ...props,
3412
+ children: withHandle ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "z-10 flex h-8 w-4 items-center justify-center rounded-sm border bg-border group-aria-[orientation=horizontal]/handle:h-4 group-aria-[orientation=horizontal]/handle:w-8", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(DragHandleDots2Icon, { className: "h-2.5 w-2.5 group-aria-[orientation=horizontal]/handle:rotate-90" }) }) : null
3413
+ }
3414
+ );
3415
+ ResizableHandle.displayName = "ResizableHandle";
3416
+
3417
+ // src/app-shell/canvas.tsx
3418
+ var import_jsx_runtime39 = require("react/jsx-runtime");
3419
+ var GAP = "bg-transparent data-[separator=hover]:bg-foreground/15 data-[separator=active]:bg-foreground/25";
3420
+ function CanvasLayout({ columns, expandedId = null, className }) {
3421
+ const visible = columns.filter((c) => c.panels.length > 0);
3422
+ const expanded = expandedId ? visible.flatMap((c) => c.panels).find((p) => p.id === expandedId) : void 0;
3423
+ if (expanded) {
3424
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { "data-slot": "canvas-layout", "data-expanded": expanded.id, className: cn2("flex h-full w-full", className), children: expanded.node });
3425
+ }
3426
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ResizablePanelGroup, { "data-slot": "canvas-layout", orientation: "horizontal", className: cn2("gap-0", className), children: visible.map((column, ci) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(React27.Fragment, { children: [
3427
+ ci > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ResizableHandle, { "data-canvas-gap": "column", size: "md", className: GAP }) : null,
3428
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3429
+ ResizablePanel,
3430
+ {
3431
+ id: column.id,
3432
+ minSize: column.minSize ?? 220,
3433
+ ...column.defaultSize !== void 0 ? { defaultSize: column.defaultSize } : {},
3434
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ResizablePanelGroup, { "data-canvas-column": column.id, orientation: "vertical", children: column.panels.map((panel, pi) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(React27.Fragment, { children: [
3435
+ pi > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ResizableHandle, { "data-canvas-gap": "row", size: "md", className: GAP }) : null,
3436
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3437
+ ResizablePanel,
3438
+ {
3439
+ id: panel.id,
3440
+ minSize: panel.minSize ?? 120,
3441
+ ...panel.defaultSize !== void 0 ? { defaultSize: panel.defaultSize } : {},
3442
+ children: panel.node
3443
+ }
3444
+ )
3445
+ ] }, panel.id)) })
3446
+ }
3447
+ )
3448
+ ] }, column.id)) });
3449
+ }
3450
+
3451
+ // src/app-shell/mode-switch.tsx
3452
+ var React28 = __toESM(require("react"), 1);
3453
+ var import_jsx_runtime40 = require("react/jsx-runtime");
3454
+ function ModeSwitch({ value, onValueChange, options, label = "Mode", className }) {
3455
+ const refs = React28.useRef([]);
3456
+ const move = (from, delta) => {
3457
+ const next = (from + delta + options.length) % options.length;
3458
+ const option = options[next];
3459
+ if (!option) return;
3460
+ onValueChange(option.value);
3461
+ refs.current[next]?.focus();
3462
+ };
3463
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3464
+ "div",
3465
+ {
3466
+ role: "radiogroup",
3467
+ "aria-label": label,
3468
+ "data-slot": "mode-switch",
3469
+ className: cn2("inline-flex items-center gap-0.5 rounded-lg bg-foreground/[0.06] p-0.5", className),
3470
+ children: options.map((option, index) => {
3471
+ const checked = option.value === value;
3472
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Tooltip, { children: [
3473
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3474
+ "button",
3475
+ {
3476
+ ref: (el) => {
3477
+ refs.current[index] = el;
3478
+ },
3479
+ type: "button",
3480
+ role: "radio",
3481
+ "aria-checked": checked,
3482
+ "aria-label": option.label,
3483
+ "data-slot": "mode-switch-item",
3484
+ "data-value": option.value,
3485
+ tabIndex: checked ? 0 : -1,
3486
+ onClick: () => onValueChange(option.value),
3487
+ onKeyDown: (event) => {
3488
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
3489
+ event.preventDefault();
3490
+ move(index, 1);
3491
+ } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
3492
+ event.preventDefault();
3493
+ move(index, -1);
3494
+ }
3495
+ },
3496
+ className: cn2(
3497
+ "flex h-6 w-7 items-center justify-center rounded-md text-foreground/55 outline-none transition-colors",
3498
+ "hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring",
3499
+ "aria-checked:bg-background aria-checked:text-foreground aria-checked:shadow-[0_0_0_0.5px_hsl(var(--foreground)/0.12),0_1px_2px_hsl(var(--foreground)/0.08)]",
3500
+ "dark:aria-checked:bg-foreground/[0.14] dark:aria-checked:shadow-none",
3501
+ "[&_svg]:size-[15px] [&_svg]:shrink-0"
3502
+ ),
3503
+ children: option.icon
3504
+ }
3505
+ ) }),
3506
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TooltipContent, { side: "bottom", align: "center", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "flex items-center gap-2", children: [
3507
+ option.label,
3508
+ option.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "opacity-60", children: option.shortcut }) : null
3509
+ ] }) })
3510
+ ] }, option.value);
3511
+ })
3512
+ }
3513
+ );
3514
+ }
3515
+
3516
+ // src/organization-picker.tsx
3517
+ var React29 = __toESM(require("react"), 1);
3518
+ var import_jsx_runtime41 = require("react/jsx-runtime");
3519
+ var ORGANIZATION_HUES = [217, 262, 330, 12, 32, 152, 189, 290];
3520
+ function organizationColor(seed) {
3521
+ let hash = 0;
3522
+ for (let index = 0; index < seed.length; index += 1) {
3523
+ hash = hash * 31 + seed.charCodeAt(index) >>> 0;
3524
+ }
3525
+ const hue = ORGANIZATION_HUES[hash % ORGANIZATION_HUES.length];
3526
+ return { background: `hsl(${hue} 62% 46%)`, color: "#fff" };
3527
+ }
3528
+ function OrganizationMark({
3529
+ id,
3530
+ name,
3531
+ abbreviation,
3532
+ logoUrl,
3533
+ size = 20,
3534
+ className
3535
+ }) {
3536
+ const box = { width: size, height: size };
3537
+ if (logoUrl) {
3538
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3539
+ "span",
3540
+ {
3541
+ style: box,
3542
+ className: cn2("relative inline-flex shrink-0 overflow-hidden rounded-md bg-muted", className),
3543
+ "data-slot": "organization-mark",
3544
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("img", { src: logoUrl, alt: name, className: "h-full w-full object-cover" })
3545
+ }
3546
+ );
3547
+ }
3548
+ const letters = (abbreviation && abbreviation.trim() || name.trim().slice(0, 1) || "?").slice(0, 3).toUpperCase();
3549
+ const fontSize = Math.round(size * (letters.length >= 3 ? 0.36 : 0.44));
3550
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3551
+ "span",
3552
+ {
3553
+ style: { ...box, ...organizationColor(id || name), fontSize },
3554
+ className: cn2(
3555
+ "inline-flex shrink-0 items-center justify-center rounded-md font-bold leading-none tracking-tight",
3556
+ className
3557
+ ),
3558
+ "aria-label": `Organization abbreviation ${letters}`,
3559
+ title: letters,
3560
+ "data-slot": "organization-mark",
3561
+ children: letters
3562
+ }
3563
+ );
3564
+ }
3565
+ //# sourceMappingURL=desktop.cjs.map