@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.
- package/CHANGELOG.md +41 -0
- package/dist/desktop-lint.mjs +218 -0
- package/dist/desktop.cjs +3565 -0
- package/dist/desktop.cjs.map +1 -0
- package/dist/desktop.css +234 -0
- package/dist/desktop.d.cts +484 -0
- package/dist/desktop.d.ts +484 -0
- package/dist/desktop.js +3533 -0
- package/dist/desktop.js.map +1 -0
- package/dist/index.d.cts +14 -876
- package/dist/index.d.ts +14 -876
- package/dist/organization-picker-mLqIcesx.d.cts +875 -0
- package/dist/organization-picker-mLqIcesx.d.ts +875 -0
- package/package.json +13 -1
package/dist/desktop.js
ADDED
|
@@ -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
|