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