@ship-it-ui/ui 0.0.1

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/dist/index.cjs ADDED
@@ -0,0 +1,3581 @@
1
+ 'use strict';
2
+
3
+ var clsx = require('clsx');
4
+ var tailwindMerge = require('tailwind-merge');
5
+ var react = require('react');
6
+ var reactSlot = require('@radix-ui/react-slot');
7
+ var classVarianceAuthority = require('class-variance-authority');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+ var RadixCheckbox = require('@radix-ui/react-checkbox');
10
+ var RadixRadio = require('@radix-ui/react-radio-group');
11
+ var RadixSelect = require('@radix-ui/react-select');
12
+ var RadixSlider = require('@radix-ui/react-slider');
13
+ var RadixSwitch = require('@radix-ui/react-switch');
14
+ var RadixAvatar = require('@radix-ui/react-avatar');
15
+ var RadixContext = require('@radix-ui/react-context-menu');
16
+ var RadixDialog = require('@radix-ui/react-dialog');
17
+ var RadixAlert = require('@radix-ui/react-alert-dialog');
18
+ var RadixMenu = require('@radix-ui/react-dropdown-menu');
19
+ var RadixHoverCard = require('@radix-ui/react-hover-card');
20
+ var RadixPopover = require('@radix-ui/react-popover');
21
+ var RadixToast = require('@radix-ui/react-toast');
22
+ var RadixTooltip = require('@radix-ui/react-tooltip');
23
+ var RadixMenubar = require('@radix-ui/react-menubar');
24
+ var RadixTabs = require('@radix-ui/react-tabs');
25
+
26
+ function _interopNamespace(e) {
27
+ if (e && e.__esModule) return e;
28
+ var n = Object.create(null);
29
+ if (e) {
30
+ Object.keys(e).forEach(function (k) {
31
+ if (k !== 'default') {
32
+ var d = Object.getOwnPropertyDescriptor(e, k);
33
+ Object.defineProperty(n, k, d.get ? d : {
34
+ enumerable: true,
35
+ get: function () { return e[k]; }
36
+ });
37
+ }
38
+ });
39
+ }
40
+ n.default = e;
41
+ return Object.freeze(n);
42
+ }
43
+
44
+ var RadixCheckbox__namespace = /*#__PURE__*/_interopNamespace(RadixCheckbox);
45
+ var RadixRadio__namespace = /*#__PURE__*/_interopNamespace(RadixRadio);
46
+ var RadixSelect__namespace = /*#__PURE__*/_interopNamespace(RadixSelect);
47
+ var RadixSlider__namespace = /*#__PURE__*/_interopNamespace(RadixSlider);
48
+ var RadixSwitch__namespace = /*#__PURE__*/_interopNamespace(RadixSwitch);
49
+ var RadixAvatar__namespace = /*#__PURE__*/_interopNamespace(RadixAvatar);
50
+ var RadixContext__namespace = /*#__PURE__*/_interopNamespace(RadixContext);
51
+ var RadixDialog__namespace = /*#__PURE__*/_interopNamespace(RadixDialog);
52
+ var RadixAlert__namespace = /*#__PURE__*/_interopNamespace(RadixAlert);
53
+ var RadixMenu__namespace = /*#__PURE__*/_interopNamespace(RadixMenu);
54
+ var RadixHoverCard__namespace = /*#__PURE__*/_interopNamespace(RadixHoverCard);
55
+ var RadixPopover__namespace = /*#__PURE__*/_interopNamespace(RadixPopover);
56
+ var RadixToast__namespace = /*#__PURE__*/_interopNamespace(RadixToast);
57
+ var RadixTooltip__namespace = /*#__PURE__*/_interopNamespace(RadixTooltip);
58
+ var RadixMenubar__namespace = /*#__PURE__*/_interopNamespace(RadixMenubar);
59
+ var RadixTabs__namespace = /*#__PURE__*/_interopNamespace(RadixTabs);
60
+
61
+ // src/utils/cn.ts
62
+ function cn(...inputs) {
63
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
64
+ }
65
+ function useControllableState({
66
+ value: controlledValue,
67
+ defaultValue,
68
+ onChange
69
+ }) {
70
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(defaultValue);
71
+ const isControlled = controlledValue !== void 0;
72
+ const value = isControlled ? controlledValue : uncontrolledValue;
73
+ const onChangeRef = react.useRef(onChange);
74
+ onChangeRef.current = onChange;
75
+ const valueRef = react.useRef(value);
76
+ valueRef.current = value;
77
+ const setValue = react.useCallback(
78
+ (next) => {
79
+ const resolved = typeof next === "function" ? next(valueRef.current) : next;
80
+ if (!isControlled) {
81
+ setUncontrolledValue(resolved);
82
+ }
83
+ if (resolved !== valueRef.current) {
84
+ onChangeRef.current?.(resolved);
85
+ }
86
+ },
87
+ [isControlled]
88
+ );
89
+ return [value, setValue];
90
+ }
91
+ function useDisclosure(initial = false) {
92
+ const [open, setOpen] = react.useState(initial);
93
+ const onOpen = react.useCallback(() => setOpen(true), []);
94
+ const onClose = react.useCallback(() => setOpen(false), []);
95
+ const onToggle = react.useCallback(() => setOpen((o) => !o), []);
96
+ return { open, onOpen, onClose, onToggle, setOpen };
97
+ }
98
+ function useEscape(handler, enabled = true) {
99
+ react.useEffect(() => {
100
+ if (!enabled) return;
101
+ const onKey = (e) => {
102
+ if (e.key === "Escape") handler();
103
+ };
104
+ window.addEventListener("keydown", onKey);
105
+ return () => window.removeEventListener("keydown", onKey);
106
+ }, [handler, enabled]);
107
+ }
108
+ function useKeyboardList({
109
+ count,
110
+ loop = true,
111
+ defaultCursor = 0,
112
+ onSelect
113
+ }) {
114
+ const [cursor, setCursor] = react.useState(defaultCursor);
115
+ const move = react.useCallback(
116
+ (delta) => {
117
+ if (count <= 0) return;
118
+ setCursor((c) => {
119
+ const next = c + delta;
120
+ if (loop) return (next % count + count) % count;
121
+ return Math.max(0, Math.min(count - 1, next));
122
+ });
123
+ },
124
+ [count, loop]
125
+ );
126
+ const onKeyDown = react.useCallback(
127
+ (event) => {
128
+ if (count <= 0) return;
129
+ switch (event.key) {
130
+ case "ArrowDown":
131
+ event.preventDefault();
132
+ move(1);
133
+ break;
134
+ case "ArrowUp":
135
+ event.preventDefault();
136
+ move(-1);
137
+ break;
138
+ case "Home":
139
+ event.preventDefault();
140
+ setCursor(0);
141
+ break;
142
+ case "End":
143
+ event.preventDefault();
144
+ setCursor(count - 1);
145
+ break;
146
+ case "Enter":
147
+ if (onSelect) {
148
+ event.preventDefault();
149
+ onSelect(cursor);
150
+ }
151
+ break;
152
+ }
153
+ },
154
+ [count, cursor, move, onSelect]
155
+ );
156
+ const safeCursor = count > 0 ? Math.min(cursor, count - 1) : 0;
157
+ return { cursor: safeCursor, setCursor, onKeyDown };
158
+ }
159
+ function useOutsideClick(ref, handler, enabled = true) {
160
+ react.useEffect(() => {
161
+ if (!enabled) return;
162
+ const onDown = (e) => {
163
+ const el = ref.current;
164
+ if (el && e.target instanceof Node && !el.contains(e.target)) handler();
165
+ };
166
+ document.addEventListener("mousedown", onDown);
167
+ return () => document.removeEventListener("mousedown", onDown);
168
+ }, [ref, handler, enabled]);
169
+ }
170
+ function useTheme() {
171
+ const [theme, setThemeState] = react.useState(() => {
172
+ if (typeof document === "undefined") return "dark";
173
+ return document.documentElement.getAttribute("data-theme") === "light" ? "light" : "dark";
174
+ });
175
+ const setTheme = react.useCallback((next) => {
176
+ if (next === "light") {
177
+ document.documentElement.setAttribute("data-theme", "light");
178
+ } else {
179
+ document.documentElement.removeAttribute("data-theme");
180
+ }
181
+ setThemeState(next);
182
+ }, []);
183
+ const toggle = react.useCallback(() => {
184
+ setTheme(theme === "dark" ? "light" : "dark");
185
+ }, [theme, setTheme]);
186
+ react.useEffect(() => {
187
+ const observer = new MutationObserver(() => {
188
+ const attr = document.documentElement.getAttribute("data-theme");
189
+ setThemeState(attr === "light" ? "light" : "dark");
190
+ });
191
+ observer.observe(document.documentElement, {
192
+ attributes: true,
193
+ attributeFilter: ["data-theme"]
194
+ });
195
+ return () => observer.disconnect();
196
+ }, []);
197
+ return { theme, setTheme, toggle };
198
+ }
199
+ var buttonStyles = classVarianceAuthority.cva(
200
+ [
201
+ "inline-flex items-center justify-center whitespace-nowrap",
202
+ "font-medium transition-[background,filter,box-shadow,color] duration-(--duration-micro)",
203
+ "outline-none",
204
+ "focus-visible:ring-[3px] focus-visible:ring-accent-dim",
205
+ "disabled:cursor-not-allowed disabled:opacity-40"
206
+ ],
207
+ {
208
+ variants: {
209
+ variant: {
210
+ primary: "bg-accent text-on-accent border border-accent hover:brightness-110 active:brightness-95",
211
+ secondary: "bg-panel-2 text-text border border-border hover:bg-[color-mix(in_oklab,var(--color-panel-2),white_4%)]",
212
+ ghost: "bg-transparent text-text border border-transparent hover:bg-panel-2",
213
+ outline: "bg-transparent text-text border border-border-strong hover:bg-panel-2",
214
+ destructive: "bg-err text-on-accent border border-err hover:brightness-110 active:brightness-95",
215
+ success: "bg-ok text-on-accent border border-ok hover:brightness-110 active:brightness-95",
216
+ link: "bg-transparent text-accent border border-transparent underline underline-offset-[3px] hover:brightness-110"
217
+ },
218
+ size: {
219
+ sm: "h-[26px] px-[10px] text-[11px] gap-[5px] rounded-[5px]",
220
+ md: "h-[32px] px-3 text-[12px] gap-[6px] rounded-md",
221
+ lg: "h-[38px] px-4 text-[13px] gap-[7px] rounded-[7px]"
222
+ },
223
+ fullWidth: {
224
+ true: "w-full",
225
+ false: ""
226
+ }
227
+ },
228
+ defaultVariants: {
229
+ variant: "primary",
230
+ size: "md",
231
+ fullWidth: false
232
+ }
233
+ }
234
+ );
235
+ function Spinner({ size }) {
236
+ return /* @__PURE__ */ jsxRuntime.jsx(
237
+ "span",
238
+ {
239
+ "aria-hidden": true,
240
+ className: "inline-block animate-[ship-spin_0.7s_linear_infinite] rounded-full border-[1.5px] border-current border-t-transparent",
241
+ style: { width: size, height: size }
242
+ }
243
+ );
244
+ }
245
+ var iconSize = { sm: 11, md: 12, lg: 13 };
246
+ var Button = react.forwardRef(function Button2({
247
+ variant,
248
+ size,
249
+ fullWidth,
250
+ icon,
251
+ trailing,
252
+ loading = false,
253
+ disabled,
254
+ asChild = false,
255
+ type,
256
+ className,
257
+ children,
258
+ ...props
259
+ }, ref) {
260
+ const isDisabled = disabled || loading;
261
+ const iconPx = iconSize[size ?? "md"];
262
+ const composedClassName = cn(buttonStyles({ variant, size, fullWidth }), className);
263
+ if (asChild) {
264
+ return /* @__PURE__ */ jsxRuntime.jsx(
265
+ reactSlot.Slot,
266
+ {
267
+ ref,
268
+ "aria-busy": loading || void 0,
269
+ "aria-disabled": isDisabled || void 0,
270
+ "data-disabled": isDisabled ? "" : void 0,
271
+ className: composedClassName,
272
+ ...props,
273
+ children
274
+ }
275
+ );
276
+ }
277
+ return /* @__PURE__ */ jsxRuntime.jsxs(
278
+ "button",
279
+ {
280
+ ref,
281
+ type: type ?? "button",
282
+ disabled: isDisabled,
283
+ "aria-busy": loading || void 0,
284
+ className: composedClassName,
285
+ ...props,
286
+ children: [
287
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: iconPx }) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex", children: icon }) : null,
288
+ children,
289
+ trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex opacity-60", children: trailing })
290
+ ]
291
+ }
292
+ );
293
+ });
294
+ Button.displayName = "Button";
295
+ var iconButtonStyles = classVarianceAuthority.cva(
296
+ [
297
+ "inline-grid place-items-center transition-[background,filter,color] duration-(--duration-micro)",
298
+ "outline-none focus-visible:ring-[3px] focus-visible:ring-accent-dim",
299
+ "disabled:cursor-not-allowed disabled:opacity-40"
300
+ ],
301
+ {
302
+ variants: {
303
+ variant: {
304
+ primary: "bg-accent text-on-accent border border-accent hover:brightness-110",
305
+ secondary: "bg-panel-2 text-text-muted border border-border hover:bg-[color-mix(in_oklab,var(--color-panel-2),white_4%)]",
306
+ ghost: "bg-transparent text-text-muted border border-transparent hover:bg-panel-2 hover:text-text",
307
+ outline: "bg-transparent text-text-muted border border-border-strong hover:bg-panel-2 hover:text-text"
308
+ },
309
+ size: {
310
+ sm: "h-[26px] w-[26px] text-[12px] rounded-[5px]",
311
+ md: "h-[32px] w-[32px] text-[13px] rounded-md",
312
+ lg: "h-[38px] w-[38px] text-[15px] rounded-[7px]"
313
+ }
314
+ },
315
+ defaultVariants: { variant: "secondary", size: "md" }
316
+ }
317
+ );
318
+ var IconButton = react.forwardRef(function IconButton2({ variant, size, icon, type, className, ...props }, ref) {
319
+ return /* @__PURE__ */ jsxRuntime.jsx(
320
+ "button",
321
+ {
322
+ ref,
323
+ type: type ?? "button",
324
+ className: cn(iconButtonStyles({ variant, size }), className),
325
+ ...props,
326
+ children: icon
327
+ }
328
+ );
329
+ });
330
+ IconButton.displayName = "IconButton";
331
+ var ButtonGroup = react.forwardRef(function ButtonGroup2({ orientation = "horizontal", className, children, ...props }, ref) {
332
+ const items = react.Children.toArray(children).filter(react.isValidElement);
333
+ return /* @__PURE__ */ jsxRuntime.jsx(
334
+ "div",
335
+ {
336
+ ref,
337
+ role: "group",
338
+ className: cn(
339
+ "border-border inline-flex overflow-hidden rounded-md border",
340
+ orientation === "vertical" ? "flex-col" : "flex-row",
341
+ className
342
+ ),
343
+ ...props,
344
+ children: items.map((child, i) => {
345
+ const isFirst = i === 0;
346
+ const childProps = child.props ?? {};
347
+ return react.cloneElement(child, {
348
+ key: i,
349
+ className: cn(
350
+ childProps.className,
351
+ "rounded-none border-none",
352
+ !isFirst && (orientation === "horizontal" ? "border-l border-l-border" : "border-t border-t-border")
353
+ )
354
+ });
355
+ })
356
+ }
357
+ );
358
+ });
359
+ ButtonGroup.displayName = "ButtonGroup";
360
+ var SplitButton = react.forwardRef(function SplitButton2({ variant = "primary", size = "md", onClick, onMenu, disabled, className, children, ...props }, ref) {
361
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("inline-flex", className), ...props, children: [
362
+ /* @__PURE__ */ jsxRuntime.jsx(
363
+ Button,
364
+ {
365
+ variant,
366
+ size,
367
+ onClick,
368
+ disabled,
369
+ className: "rounded-r-none border-r border-r-black/20",
370
+ children
371
+ }
372
+ ),
373
+ /* @__PURE__ */ jsxRuntime.jsx(
374
+ Button,
375
+ {
376
+ variant,
377
+ size,
378
+ onClick: onMenu,
379
+ disabled,
380
+ "aria-label": "More actions",
381
+ className: "rounded-l-none px-2",
382
+ children: "\u25BE"
383
+ }
384
+ )
385
+ ] });
386
+ });
387
+ SplitButton.displayName = "SplitButton";
388
+ var FAB = react.forwardRef(function FAB2({ icon = "\u2726", type, className, style, ...props }, ref) {
389
+ return /* @__PURE__ */ jsxRuntime.jsx(
390
+ "button",
391
+ {
392
+ ref,
393
+ type: type ?? "button",
394
+ className: cn(
395
+ "grid h-12 w-12 place-items-center rounded-full",
396
+ "bg-accent text-on-accent text-lg font-semibold",
397
+ "shadow-[0_10px_30px_var(--color-accent-glow),0_2px_6px_rgba(0,0,0,0.4)]",
398
+ "transition-[transform,box-shadow] duration-200",
399
+ "hover:-translate-y-px hover:shadow-[0_14px_36px_var(--color-accent-glow),0_4px_10px_rgba(0,0,0,0.45)]",
400
+ "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]",
401
+ "disabled:cursor-not-allowed disabled:opacity-40",
402
+ className
403
+ ),
404
+ style,
405
+ ...props,
406
+ children: icon
407
+ }
408
+ );
409
+ });
410
+ FAB.displayName = "FAB";
411
+ var Checkbox = react.forwardRef(function Checkbox2({ label, className, id: idProp, ...props }, ref) {
412
+ const reactId = react.useId();
413
+ const id = idProp ?? `cb-${reactId}`;
414
+ return /* @__PURE__ */ jsxRuntime.jsxs(
415
+ "span",
416
+ {
417
+ className: cn(
418
+ "inline-flex items-center gap-2 select-none",
419
+ props.disabled && "cursor-not-allowed opacity-40",
420
+ className
421
+ ),
422
+ children: [
423
+ /* @__PURE__ */ jsxRuntime.jsx(
424
+ RadixCheckbox__namespace.Root,
425
+ {
426
+ ref,
427
+ id,
428
+ className: cn(
429
+ "grid h-4 w-4 place-items-center rounded-xs",
430
+ "bg-panel border-border-strong border",
431
+ "data-[state=checked]:bg-accent data-[state=checked]:border-accent",
432
+ "data-[state=indeterminate]:bg-accent data-[state=indeterminate]:border-accent",
433
+ "transition-[background,border-color] duration-(--duration-micro)",
434
+ "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]"
435
+ ),
436
+ ...props,
437
+ children: /* @__PURE__ */ jsxRuntime.jsx(RadixCheckbox__namespace.Indicator, { className: "text-on-accent text-[11px] leading-none", children: props.checked === "indeterminate" ? "\u2212" : "\u2713" })
438
+ }
439
+ ),
440
+ label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "cursor-pointer text-[13px]", children: label })
441
+ ]
442
+ }
443
+ );
444
+ });
445
+ Checkbox.displayName = "Checkbox";
446
+ function Field({ label, hint, error, required, className, children, ...props }) {
447
+ const reactId = react.useId();
448
+ const id = `field-${reactId}`;
449
+ const hintId = hint && !error ? `${id}-hint` : void 0;
450
+ const errorId = error ? `${id}-error` : void 0;
451
+ const describedBy = errorId ?? hintId;
452
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-[6px]", className), ...props, children: [
453
+ label && /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: id, className: "text-text-muted text-[11px] font-medium", children: [
454
+ label,
455
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-err ml-1", children: "*" })
456
+ ] }),
457
+ children({
458
+ id,
459
+ "aria-describedby": describedBy,
460
+ "aria-invalid": error ? true : void 0
461
+ }),
462
+ hint && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { id: hintId, className: "text-text-dim text-[11px]", children: hint }),
463
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, className: "text-err text-[11px]", children: error })
464
+ ] });
465
+ }
466
+ var inputWrapperStyles = classVarianceAuthority.cva(
467
+ [
468
+ "flex items-center gap-[6px] font-sans transition-[border-color,box-shadow] duration-(--duration-micro)",
469
+ "border focus-within:ring-[3px]",
470
+ "has-[:disabled]:opacity-50 has-[:disabled]:bg-panel-2"
471
+ ],
472
+ {
473
+ variants: {
474
+ size: {
475
+ sm: "h-7 px-2 text-[12px] rounded-md",
476
+ md: "h-[34px] px-[10px] text-[13px] rounded-md",
477
+ lg: "h-10 px-3 text-[14px] rounded-md"
478
+ },
479
+ tone: {
480
+ default: "bg-panel border-border focus-within:border-accent focus-within:ring-accent-dim",
481
+ error: "bg-panel border-err focus-within:border-err focus-within:ring-[oklch(0.55_0.18_30/0.18)]"
482
+ }
483
+ },
484
+ defaultVariants: { size: "md", tone: "default" }
485
+ }
486
+ );
487
+ var Input = react.forwardRef(function Input2({ size, tone, icon, trailing, error, width, className, style, disabled, ...props }, ref) {
488
+ const computedTone = error ? "error" : tone;
489
+ return /* @__PURE__ */ jsxRuntime.jsxs(
490
+ "div",
491
+ {
492
+ className: cn(inputWrapperStyles({ size, tone: computedTone }), className),
493
+ style: { width, ...style },
494
+ children: [
495
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim leading-none", children: icon }),
496
+ /* @__PURE__ */ jsxRuntime.jsx(
497
+ "input",
498
+ {
499
+ ref,
500
+ disabled,
501
+ "aria-invalid": error || void 0,
502
+ className: cn(
503
+ "text-text min-w-0 flex-1 border-none bg-transparent font-sans outline-none",
504
+ "placeholder:text-text-dim",
505
+ "disabled:cursor-not-allowed"
506
+ ),
507
+ ...props
508
+ }
509
+ ),
510
+ trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim text-[11px]", children: trailing })
511
+ ]
512
+ }
513
+ );
514
+ });
515
+ Input.displayName = "Input";
516
+ var SearchInput = react.forwardRef(function SearchInput2({ shortcut = "\u2318K", width = 360, className, style, placeholder = "Search\u2026", ...props }, ref) {
517
+ return /* @__PURE__ */ jsxRuntime.jsxs(
518
+ "div",
519
+ {
520
+ className: cn(
521
+ "rounded-base flex h-9 items-center gap-2 px-3 font-sans",
522
+ "bg-panel-2 border-border border",
523
+ "focus-within:border-accent focus-within:ring-accent-dim focus-within:ring-[3px]",
524
+ "transition-[border-color,box-shadow] duration-(--duration-micro)",
525
+ className
526
+ ),
527
+ style: { width, ...style },
528
+ children: [
529
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim leading-none", children: "\u2315" }),
530
+ /* @__PURE__ */ jsxRuntime.jsx(
531
+ "input",
532
+ {
533
+ ref,
534
+ type: "search",
535
+ placeholder,
536
+ className: "text-text placeholder:text-text-dim min-w-0 flex-1 border-none bg-transparent text-[13px] outline-none",
537
+ ...props
538
+ }
539
+ ),
540
+ shortcut && /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-text-dim border-border rounded-xs border px-[6px] py-[2px] font-mono text-[10px]", children: shortcut })
541
+ ]
542
+ }
543
+ );
544
+ });
545
+ SearchInput.displayName = "SearchInput";
546
+ var OTP = react.forwardRef(function OTP2({ length = 6, onComplete, onChange, defaultValue = "", ariaLabel = "Code", className, disabled }, ref) {
547
+ const baseId = react.useId();
548
+ const refs = react.useRef([]);
549
+ const [values, setValues] = react.useState(
550
+ () => Array.from({ length }, (_, i) => defaultValue[i] ?? "")
551
+ );
552
+ react.useImperativeHandle(ref, () => ({
553
+ focus: () => refs.current[0]?.focus(),
554
+ reset: () => {
555
+ setValues(Array(length).fill(""));
556
+ refs.current[0]?.focus();
557
+ }
558
+ }));
559
+ const writeAt = (i, char) => {
560
+ if (!/^\d?$/.test(char)) return;
561
+ setValues((prev) => {
562
+ const next = [...prev];
563
+ next[i] = char;
564
+ const joined = next.join("");
565
+ onChange?.(joined);
566
+ if (joined.length === length && next.every((c) => c)) onComplete?.(joined);
567
+ return next;
568
+ });
569
+ if (char && i < length - 1) refs.current[i + 1]?.focus();
570
+ };
571
+ const onKey = (i, e) => {
572
+ if (e.key === "Backspace" && !values[i] && i > 0) {
573
+ refs.current[i - 1]?.focus();
574
+ } else if (e.key === "ArrowLeft" && i > 0) {
575
+ refs.current[i - 1]?.focus();
576
+ } else if (e.key === "ArrowRight" && i < length - 1) {
577
+ refs.current[i + 1]?.focus();
578
+ }
579
+ };
580
+ const onPaste = (e) => {
581
+ const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, length);
582
+ if (!pasted) return;
583
+ e.preventDefault();
584
+ const next = Array.from({ length }, (_, i) => pasted[i] ?? "");
585
+ setValues(next);
586
+ const joined = next.join("");
587
+ onChange?.(joined);
588
+ if (joined.length === length) onComplete?.(joined);
589
+ refs.current[Math.min(pasted.length, length - 1)]?.focus();
590
+ };
591
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-2", className), children: values.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx(
592
+ "input",
593
+ {
594
+ id: `${baseId}-${i}`,
595
+ ref: (el) => {
596
+ refs.current[i] = el;
597
+ },
598
+ inputMode: "numeric",
599
+ autoComplete: "one-time-code",
600
+ maxLength: 1,
601
+ value: c,
602
+ disabled,
603
+ "aria-label": `${ariaLabel} ${i + 1} of ${length}`,
604
+ onChange: (e) => writeAt(i, e.target.value),
605
+ onKeyDown: (e) => onKey(i, e),
606
+ onFocus: (e) => e.target.select(),
607
+ onPaste: i === 0 ? onPaste : void 0,
608
+ className: cn(
609
+ "text-text bg-panel h-12 w-10 rounded-md text-center font-mono text-[20px] font-medium",
610
+ "border-border border transition-[border-color,box-shadow] duration-(--duration-micro) outline-none",
611
+ "focus:border-accent focus:ring-accent-dim focus:ring-[3px]",
612
+ "disabled:cursor-not-allowed disabled:opacity-50"
613
+ )
614
+ },
615
+ i
616
+ )) });
617
+ });
618
+ OTP.displayName = "OTP";
619
+ var RadioGroup = react.forwardRef(function RadioGroup2({ className, ...props }, ref) {
620
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixRadio__namespace.Root, { ref, className: cn("flex flex-col gap-2", className), ...props });
621
+ });
622
+ RadioGroup.displayName = "RadioGroup";
623
+ var Radio = react.forwardRef(function Radio2({ label, className, id: idProp, ...props }, ref) {
624
+ const reactId = react.useId();
625
+ const id = idProp ?? `radio-${reactId}`;
626
+ return /* @__PURE__ */ jsxRuntime.jsxs(
627
+ "span",
628
+ {
629
+ className: cn(
630
+ "inline-flex items-center gap-2 select-none",
631
+ props.disabled && "cursor-not-allowed opacity-40",
632
+ className
633
+ ),
634
+ children: [
635
+ /* @__PURE__ */ jsxRuntime.jsx(
636
+ RadixRadio__namespace.Item,
637
+ {
638
+ ref,
639
+ id,
640
+ className: cn(
641
+ "grid h-4 w-4 place-items-center rounded-full",
642
+ "bg-panel border-border-strong border",
643
+ "data-[state=checked]:border-accent",
644
+ "transition-[border-color] duration-(--duration-micro)",
645
+ "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]"
646
+ ),
647
+ ...props,
648
+ children: /* @__PURE__ */ jsxRuntime.jsx(RadixRadio__namespace.Indicator, { className: "bg-accent block h-[7px] w-[7px] rounded-full" })
649
+ }
650
+ ),
651
+ label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "cursor-pointer text-[13px]", children: label })
652
+ ]
653
+ }
654
+ );
655
+ });
656
+ Radio.displayName = "Radio";
657
+ var SelectRoot = RadixSelect__namespace.Root;
658
+ var SelectValue = RadixSelect__namespace.Value;
659
+ var SelectGroup = RadixSelect__namespace.Group;
660
+ var SelectLabel = RadixSelect__namespace.Label;
661
+ var triggerClasses = {
662
+ sm: "h-7 px-2 text-[12px]",
663
+ md: "h-[34px] px-[10px] text-[13px]",
664
+ lg: "h-10 px-3 text-[14px]"
665
+ };
666
+ var SelectTrigger = react.forwardRef(function SelectTrigger2({ size = "md", className, children, ...props }, ref) {
667
+ return /* @__PURE__ */ jsxRuntime.jsxs(
668
+ RadixSelect__namespace.Trigger,
669
+ {
670
+ ref,
671
+ className: cn(
672
+ "text-text bg-panel border-border inline-flex items-center justify-between gap-2 rounded-md border font-sans",
673
+ "data-[state=open]:border-accent",
674
+ "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]",
675
+ "data-[disabled]:bg-panel-2 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
676
+ "transition-[border-color,box-shadow] duration-(--duration-micro)",
677
+ triggerClasses[size],
678
+ className
679
+ ),
680
+ ...props,
681
+ children: [
682
+ children,
683
+ /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Icon, { className: "text-text-dim text-[11px] leading-none", children: "\u25BE" })
684
+ ]
685
+ }
686
+ );
687
+ });
688
+ SelectTrigger.displayName = "SelectTrigger";
689
+ var SelectContent = react.forwardRef(
690
+ function SelectContent2({ className, children, position = "popper", sideOffset = 6, ...props }, ref) {
691
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
692
+ RadixSelect__namespace.Content,
693
+ {
694
+ ref,
695
+ position,
696
+ sideOffset,
697
+ className: cn(
698
+ "bg-panel border-border z-50 min-w-[var(--radix-select-trigger-width)] rounded-md border p-1 shadow",
699
+ "data-[state=open]:animate-[ship-pop-in_140ms_var(--easing-out)]",
700
+ className
701
+ ),
702
+ ...props,
703
+ children: /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Viewport, { children })
704
+ }
705
+ ) });
706
+ }
707
+ );
708
+ SelectContent.displayName = "SelectContent";
709
+ var SelectItem = react.forwardRef(
710
+ function SelectItem2({ className, children, ...props }, ref) {
711
+ return /* @__PURE__ */ jsxRuntime.jsx(
712
+ RadixSelect__namespace.Item,
713
+ {
714
+ ref,
715
+ className: cn(
716
+ "relative flex cursor-pointer items-center rounded-sm px-2 py-[6px] text-[13px] outline-none",
717
+ "data-[highlighted]:bg-accent-dim data-[highlighted]:text-accent",
718
+ "data-[state=checked]:font-medium",
719
+ "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-40",
720
+ className
721
+ ),
722
+ ...props,
723
+ children: /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.ItemText, { children })
724
+ }
725
+ );
726
+ }
727
+ );
728
+ SelectItem.displayName = "SelectItem";
729
+ function Select({
730
+ options,
731
+ placeholder = "Select\u2026",
732
+ size,
733
+ className,
734
+ "aria-label": ariaLabel,
735
+ "aria-labelledby": ariaLabelledBy,
736
+ ...rootProps
737
+ }) {
738
+ return /* @__PURE__ */ jsxRuntime.jsxs(RadixSelect__namespace.Root, { ...rootProps, children: [
739
+ /* @__PURE__ */ jsxRuntime.jsx(
740
+ SelectTrigger,
741
+ {
742
+ size,
743
+ className,
744
+ "aria-label": ariaLabel,
745
+ "aria-labelledby": ariaLabelledBy,
746
+ children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder })
747
+ }
748
+ ),
749
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: options.map((opt) => {
750
+ const value = typeof opt === "string" ? opt : opt.value;
751
+ const label = typeof opt === "string" ? opt : opt.label;
752
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value, children: label }, value);
753
+ }) })
754
+ ] });
755
+ }
756
+ var Slider = react.forwardRef(function Slider2({ showValue, width = 240, className, value, defaultValue, ...props }, ref) {
757
+ const arrValue = Array.isArray(value) ? value : value !== void 0 ? [value] : void 0;
758
+ const arrDefault = Array.isArray(defaultValue) ? defaultValue : defaultValue !== void 0 ? [defaultValue] : void 0;
759
+ const display = arrValue?.[0] ?? arrDefault?.[0] ?? props.min ?? 0;
760
+ return /* @__PURE__ */ jsxRuntime.jsxs(
761
+ "span",
762
+ {
763
+ ref,
764
+ className: cn("inline-flex items-center gap-[10px]", className),
765
+ style: { width },
766
+ children: [
767
+ /* @__PURE__ */ jsxRuntime.jsxs(
768
+ RadixSlider__namespace.Root,
769
+ {
770
+ value: arrValue,
771
+ defaultValue: arrDefault,
772
+ className: "relative flex h-4 flex-1 touch-none items-center select-none",
773
+ ...props,
774
+ children: [
775
+ /* @__PURE__ */ jsxRuntime.jsx(RadixSlider__namespace.Track, { className: "bg-panel-2 relative h-1 grow rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx(RadixSlider__namespace.Range, { className: "bg-accent absolute h-full rounded-full" }) }),
776
+ /* @__PURE__ */ jsxRuntime.jsx(
777
+ RadixSlider__namespace.Thumb,
778
+ {
779
+ className: cn(
780
+ "bg-text border-accent block h-[14px] w-[14px] rounded-full border-2 shadow",
781
+ "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]",
782
+ "cursor-grab active:cursor-grabbing"
783
+ ),
784
+ "aria-label": "Value"
785
+ }
786
+ )
787
+ ]
788
+ }
789
+ ),
790
+ showValue && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-muted min-w-[28px] text-right font-mono text-[11px]", children: display })
791
+ ]
792
+ }
793
+ );
794
+ });
795
+ Slider.displayName = "Slider";
796
+ var trackClasses = {
797
+ sm: "h-4 w-7",
798
+ md: "h-5 w-9"
799
+ };
800
+ var thumbClasses = {
801
+ sm: "h-3 w-3 data-[state=checked]:translate-x-3",
802
+ md: "h-4 w-4 data-[state=checked]:translate-x-4"
803
+ };
804
+ var Switch = react.forwardRef(function Switch2({ label, size = "md", className, id: idProp, ...props }, ref) {
805
+ const reactId = react.useId();
806
+ const id = idProp ?? `sw-${reactId}`;
807
+ return /* @__PURE__ */ jsxRuntime.jsxs(
808
+ "span",
809
+ {
810
+ className: cn(
811
+ "inline-flex items-center gap-2 select-none",
812
+ props.disabled && "cursor-not-allowed opacity-40",
813
+ className
814
+ ),
815
+ children: [
816
+ /* @__PURE__ */ jsxRuntime.jsx(
817
+ RadixSwitch__namespace.Root,
818
+ {
819
+ ref,
820
+ id,
821
+ className: cn(
822
+ "relative inline-flex shrink-0 cursor-pointer rounded-full border transition-colors duration-(--duration-micro)",
823
+ "bg-panel-2 border-border data-[state=checked]:bg-accent data-[state=checked]:border-accent",
824
+ "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]",
825
+ "disabled:cursor-not-allowed",
826
+ trackClasses[size]
827
+ ),
828
+ ...props,
829
+ children: /* @__PURE__ */ jsxRuntime.jsx(
830
+ RadixSwitch__namespace.Thumb,
831
+ {
832
+ className: cn(
833
+ "bg-text absolute top-1/2 left-[1px] -translate-y-1/2 rounded-full shadow-sm",
834
+ "data-[state=checked]:bg-on-accent transition-transform duration-(--duration-micro)",
835
+ thumbClasses[size]
836
+ )
837
+ }
838
+ )
839
+ }
840
+ ),
841
+ label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "cursor-pointer text-[13px]", children: label })
842
+ ]
843
+ }
844
+ );
845
+ });
846
+ Switch.displayName = "Switch";
847
+ var textareaStyles = classVarianceAuthority.cva(
848
+ [
849
+ "w-full font-sans text-text bg-panel rounded-md p-[10px]",
850
+ "border outline-none transition-[border-color,box-shadow] duration-(--duration-micro)",
851
+ "placeholder:text-text-dim resize-y",
852
+ "focus-visible:ring-[3px]",
853
+ "disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-panel-2"
854
+ ],
855
+ {
856
+ variants: {
857
+ tone: {
858
+ default: "border-border focus-visible:border-accent focus-visible:ring-accent-dim",
859
+ error: "border-err focus-visible:border-err focus-visible:ring-[oklch(0.55_0.18_30/0.18)]"
860
+ }
861
+ },
862
+ defaultVariants: { tone: "default" }
863
+ }
864
+ );
865
+ var Textarea = react.forwardRef(function Textarea2({ tone, error, rows = 4, className, ...props }, ref) {
866
+ return /* @__PURE__ */ jsxRuntime.jsx(
867
+ "textarea",
868
+ {
869
+ ref,
870
+ rows,
871
+ "aria-invalid": error || void 0,
872
+ className: cn(textareaStyles({ tone: error ? "error" : tone }), className),
873
+ ...props
874
+ }
875
+ );
876
+ });
877
+ Textarea.displayName = "Textarea";
878
+ var sizePx = { xs: 20, sm: 24, md: 32, lg: 40, xl: 56 };
879
+ var statusBg = {
880
+ ok: "bg-ok",
881
+ warn: "bg-warn",
882
+ err: "bg-err",
883
+ off: "bg-text-dim"
884
+ };
885
+ function initialsFor(name) {
886
+ return (name || "?").split(/\s+/).map((p) => p[0] ?? "").join("").slice(0, 2).toUpperCase();
887
+ }
888
+ function hashHue(str) {
889
+ let h = 0;
890
+ for (let i = 0; i < str.length; i++) h = (h * 31 + str.charCodeAt(i)) % 360;
891
+ return h;
892
+ }
893
+ var Avatar = react.forwardRef(function Avatar2({ name = "?", src, size = "md", status, initials, className, style, ...props }, ref) {
894
+ const dim = sizePx[size];
895
+ const hue = hashHue(name);
896
+ const computedInitials = initials ?? initialsFor(name);
897
+ return /* @__PURE__ */ jsxRuntime.jsxs(
898
+ "span",
899
+ {
900
+ ref,
901
+ className: cn("relative inline-block", className),
902
+ style: { width: dim, height: dim, ...style },
903
+ ...props,
904
+ children: [
905
+ /* @__PURE__ */ jsxRuntime.jsxs(
906
+ RadixAvatar__namespace.Root,
907
+ {
908
+ className: "border-border relative inline-flex h-full w-full shrink-0 overflow-hidden rounded-full border",
909
+ style: { background: src ? void 0 : `oklch(0.4 0.1 ${hue})` },
910
+ children: [
911
+ src && /* @__PURE__ */ jsxRuntime.jsx(RadixAvatar__namespace.Image, { src, alt: name, className: "h-full w-full object-cover" }),
912
+ /* @__PURE__ */ jsxRuntime.jsx(
913
+ RadixAvatar__namespace.Fallback,
914
+ {
915
+ className: "flex h-full w-full items-center justify-center font-sans font-semibold text-white",
916
+ style: { fontSize: dim * 0.38 },
917
+ children: computedInitials
918
+ }
919
+ )
920
+ ]
921
+ }
922
+ ),
923
+ status && /* @__PURE__ */ jsxRuntime.jsx(
924
+ "span",
925
+ {
926
+ role: "img",
927
+ "aria-label": `status: ${status}`,
928
+ className: cn(
929
+ "border-bg absolute right-0 bottom-0 rounded-full border-[2px]",
930
+ statusBg[status]
931
+ ),
932
+ style: { width: dim * 0.3, height: dim * 0.3 }
933
+ }
934
+ )
935
+ ]
936
+ }
937
+ );
938
+ });
939
+ Avatar.displayName = "Avatar";
940
+ var sizePx2 = { xs: 20, sm: 24, md: 32, lg: 40, xl: 56 };
941
+ var AvatarGroup = react.forwardRef(function AvatarGroup2({ names, max = 3, size = "md", className, ...props }, ref) {
942
+ const dim = sizePx2[size];
943
+ const visible = names.slice(0, max);
944
+ const rest = names.length - visible.length;
945
+ const overlap = -dim * 0.35;
946
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("inline-flex", className), ...props, children: [
947
+ visible.map((n, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: i === 0 ? 0 : overlap }, children: /* @__PURE__ */ jsxRuntime.jsx(Avatar, { name: n, size }) }, `${n}-${i}`)),
948
+ rest > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
949
+ "span",
950
+ {
951
+ "aria-label": `+${rest} more`,
952
+ className: "bg-panel-2 border-border text-text-muted grid place-items-center rounded-full border font-mono",
953
+ style: {
954
+ width: dim,
955
+ height: dim,
956
+ marginLeft: overlap,
957
+ fontSize: dim * 0.35
958
+ },
959
+ children: [
960
+ "+",
961
+ rest
962
+ ]
963
+ }
964
+ )
965
+ ] });
966
+ });
967
+ AvatarGroup.displayName = "AvatarGroup";
968
+ var badgeStyles = classVarianceAuthority.cva("inline-flex items-center font-sans leading-none whitespace-nowrap", {
969
+ variants: {
970
+ variant: {
971
+ neutral: "bg-panel-2 text-text-muted border border-border",
972
+ accent: "bg-accent-dim text-accent border border-transparent",
973
+ ok: "bg-[color-mix(in_oklab,var(--color-ok),transparent_85%)] text-ok border border-transparent",
974
+ warn: "bg-[color-mix(in_oklab,var(--color-warn),transparent_85%)] text-warn border border-transparent",
975
+ err: "bg-[color-mix(in_oklab,var(--color-err),transparent_85%)] text-err border border-transparent",
976
+ purple: "bg-[color-mix(in_oklab,var(--color-purple),transparent_85%)] text-purple border border-transparent",
977
+ pink: "bg-[color-mix(in_oklab,var(--color-pink),transparent_85%)] text-pink border border-transparent",
978
+ outline: "bg-transparent text-text border border-border-strong",
979
+ solid: "bg-text text-bg border border-text"
980
+ },
981
+ size: {
982
+ sm: "h-[18px] px-[6px] py-[1px] text-[10px] gap-1 rounded-full",
983
+ md: "h-[22px] px-2 py-[2px] text-[11px] gap-[5px] rounded-full",
984
+ lg: "h-[26px] px-[10px] py-[3px] text-[12px] gap-[6px] rounded-full"
985
+ }
986
+ },
987
+ defaultVariants: { variant: "neutral", size: "md" }
988
+ });
989
+ var dotColorClass = {
990
+ neutral: "bg-text-dim",
991
+ accent: "bg-accent",
992
+ ok: "bg-ok",
993
+ warn: "bg-warn",
994
+ err: "bg-err",
995
+ purple: "bg-purple",
996
+ pink: "bg-pink",
997
+ outline: "bg-text-muted",
998
+ solid: "bg-bg"
999
+ };
1000
+ var dotSize = { sm: "h-[5px] w-[5px]", md: "h-[6px] w-[6px]", lg: "h-[7px] w-[7px]" };
1001
+ var Badge = react.forwardRef(function Badge2({ variant = "neutral", size = "md", dot, icon, className, children, ...props }, ref) {
1002
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { ref, className: cn(badgeStyles({ variant, size }), className), ...props, children: [
1003
+ dot && /* @__PURE__ */ jsxRuntime.jsx(
1004
+ "span",
1005
+ {
1006
+ "aria-hidden": true,
1007
+ className: cn("inline-block rounded-full", dotSize[size], dotColorClass[variant])
1008
+ }
1009
+ ),
1010
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex leading-none", children: icon }),
1011
+ children
1012
+ ] });
1013
+ });
1014
+ Badge.displayName = "Badge";
1015
+ var cardStyles = classVarianceAuthority.cva(
1016
+ "block bg-panel border border-border rounded-base transition-[border-color,transform,box-shadow] duration-(--duration-step)",
1017
+ {
1018
+ variants: {
1019
+ variant: {
1020
+ default: "",
1021
+ ghost: "bg-transparent",
1022
+ elevated: "shadow"
1023
+ },
1024
+ interactive: {
1025
+ true: "cursor-pointer hover:border-border-strong hover:-translate-y-px hover:shadow",
1026
+ false: ""
1027
+ }
1028
+ },
1029
+ defaultVariants: { variant: "default", interactive: false }
1030
+ }
1031
+ );
1032
+ var Card = react.forwardRef(function Card2({
1033
+ variant,
1034
+ interactive,
1035
+ title,
1036
+ description,
1037
+ actions,
1038
+ footer,
1039
+ className,
1040
+ children,
1041
+ onClick,
1042
+ ...props
1043
+ }, ref) {
1044
+ const isInteractive = interactive ?? Boolean(onClick);
1045
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1046
+ "div",
1047
+ {
1048
+ ref,
1049
+ onClick,
1050
+ onKeyDown: isInteractive && onClick ? (e) => {
1051
+ if (e.key === "Enter" || e.key === " ") {
1052
+ e.preventDefault();
1053
+ onClick(e);
1054
+ }
1055
+ } : void 0,
1056
+ role: isInteractive ? "button" : void 0,
1057
+ tabIndex: isInteractive ? 0 : void 0,
1058
+ className: cn(cardStyles({ variant, interactive: isInteractive }), "p-[18px]", className),
1059
+ ...props,
1060
+ children: [
1061
+ (title || actions) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-start gap-3", (description || children) && "mb-[10px]"), children: [
1062
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 text-[14px] font-medium", children: title }),
1063
+ actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1", children: actions })
1064
+ ] }),
1065
+ description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-text-muted text-[12px] leading-[1.55]", children && "mb-[14px]"), children: description }),
1066
+ children,
1067
+ footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-border text-text-dim mt-[14px] border-t pt-3 text-[11px]", children: footer })
1068
+ ]
1069
+ }
1070
+ );
1071
+ });
1072
+ Card.displayName = "Card";
1073
+ var trendClasses = {
1074
+ up: "text-ok",
1075
+ down: "text-err",
1076
+ flat: "text-text-dim"
1077
+ };
1078
+ var trendArrows = { up: "\u2191", down: "\u2193", flat: "\u2192" };
1079
+ var StatCard = react.forwardRef(function StatCard2({ label, value, delta, trend = "flat", icon, className, ...props }, ref) {
1080
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1081
+ "div",
1082
+ {
1083
+ ref,
1084
+ className: cn("bg-panel border-border rounded-base block border p-[18px]", className),
1085
+ ...props,
1086
+ children: [
1087
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-[10px] flex items-center justify-between", children: [
1088
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-dim font-mono text-[10px] tracking-wide uppercase", children: label }),
1089
+ icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-dim text-[14px]", children: icon })
1090
+ ] }),
1091
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text font-mono text-[26px] leading-none font-medium tracking-tight", children: value }),
1092
+ delta !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("mt-[6px] font-mono text-[11px]", trendClasses[trend]), children: [
1093
+ trendArrows[trend],
1094
+ " ",
1095
+ delta
1096
+ ] })
1097
+ ]
1098
+ }
1099
+ );
1100
+ });
1101
+ StatCard.displayName = "StatCard";
1102
+ var Chip = react.forwardRef(function Chip2({ icon, removable, onRemove, className, children, ...props }, ref) {
1103
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1104
+ "span",
1105
+ {
1106
+ ref,
1107
+ className: cn(
1108
+ "inline-flex h-[26px] items-center gap-[6px] py-[4px] pr-1 pl-[10px] font-sans text-[12px]",
1109
+ "bg-panel-2 text-text border-border rounded-full border",
1110
+ className
1111
+ ),
1112
+ ...props,
1113
+ children: [
1114
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim inline-flex text-[10px]", children: icon }),
1115
+ children,
1116
+ removable && /* @__PURE__ */ jsxRuntime.jsx(
1117
+ "button",
1118
+ {
1119
+ type: "button",
1120
+ onClick: onRemove,
1121
+ "aria-label": "Remove",
1122
+ className: "bg-panel text-text-dim hover:text-text grid h-[18px] w-[18px] place-items-center rounded-full text-[10px] leading-none",
1123
+ children: "\xD7"
1124
+ }
1125
+ )
1126
+ ]
1127
+ }
1128
+ );
1129
+ });
1130
+ Chip.displayName = "Chip";
1131
+ var Kbd = react.forwardRef(function Kbd2({ className, children, ...props }, ref) {
1132
+ return /* @__PURE__ */ jsxRuntime.jsx(
1133
+ "kbd",
1134
+ {
1135
+ ref,
1136
+ className: cn(
1137
+ "text-text-muted inline-flex items-center font-mono text-[10px] font-medium",
1138
+ "bg-panel border-border rounded-xs border px-[6px] py-[2px]",
1139
+ "border-b-border border-b-[2px]",
1140
+ className
1141
+ ),
1142
+ ...props,
1143
+ children
1144
+ }
1145
+ );
1146
+ });
1147
+ Kbd.displayName = "Kbd";
1148
+ var skeletonStyles = classVarianceAuthority.cva("block bg-panel-2 animate-[ship-skeleton_1.4s_infinite]", {
1149
+ variants: {
1150
+ shape: {
1151
+ line: "rounded-xs",
1152
+ block: "rounded-md",
1153
+ circle: "rounded-full"
1154
+ }
1155
+ },
1156
+ defaultVariants: { shape: "line" }
1157
+ });
1158
+ var defaultHeight = { line: 14, block: 80, circle: 40 };
1159
+ var Skeleton = react.forwardRef(function Skeleton2({ shape = "line", width = "100%", height, className, style, ...props }, ref) {
1160
+ const h = height ?? defaultHeight[shape];
1161
+ const w = shape === "circle" ? h : width;
1162
+ return /* @__PURE__ */ jsxRuntime.jsx(
1163
+ "div",
1164
+ {
1165
+ ref,
1166
+ role: "status",
1167
+ "aria-busy": "true",
1168
+ "aria-label": "Loading",
1169
+ className: cn(skeletonStyles({ shape }), className),
1170
+ style: { width: w, height: h, ...style },
1171
+ ...props
1172
+ }
1173
+ );
1174
+ });
1175
+ Skeleton.displayName = "Skeleton";
1176
+ var stateColor = {
1177
+ ok: "bg-ok",
1178
+ warn: "bg-warn",
1179
+ err: "bg-err",
1180
+ off: "bg-text-dim",
1181
+ sync: "bg-accent",
1182
+ accent: "bg-accent"
1183
+ };
1184
+ var stateText = {
1185
+ ok: "text-ok",
1186
+ warn: "text-warn",
1187
+ err: "text-err",
1188
+ off: "text-text-dim",
1189
+ sync: "text-accent",
1190
+ accent: "text-accent"
1191
+ };
1192
+ var StatusDot = react.forwardRef(function StatusDot2({ state = "ok", label, pulse, size = 8, className, ...props }, ref) {
1193
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1194
+ "span",
1195
+ {
1196
+ ref,
1197
+ role: label ? "status" : "img",
1198
+ "aria-label": !label && typeof state === "string" ? state : void 0,
1199
+ className: cn("inline-flex items-center gap-[6px]", className),
1200
+ ...props,
1201
+ children: [
1202
+ /* @__PURE__ */ jsxRuntime.jsx(
1203
+ "span",
1204
+ {
1205
+ className: cn(
1206
+ "inline-block rounded-full",
1207
+ stateColor[state],
1208
+ pulse && "animate-[ship-pulse-ring_1.6s_infinite]",
1209
+ stateText[state]
1210
+ ),
1211
+ style: { width: size, height: size }
1212
+ }
1213
+ ),
1214
+ label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-muted text-[12px]", children: label })
1215
+ ]
1216
+ }
1217
+ );
1218
+ });
1219
+ StatusDot.displayName = "StatusDot";
1220
+ var Tag = react.forwardRef(function Tag2({ onRemove, icon, size = 22, className, children, ...props }, ref) {
1221
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1222
+ "span",
1223
+ {
1224
+ ref,
1225
+ className: cn(
1226
+ "inline-flex items-center gap-[6px] px-2 py-[3px] font-sans text-[11px]",
1227
+ "bg-panel-2 text-text border-border rounded-xs border",
1228
+ className
1229
+ ),
1230
+ style: { height: size },
1231
+ ...props,
1232
+ children: [
1233
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim inline-flex", children: icon }),
1234
+ children,
1235
+ onRemove && /* @__PURE__ */ jsxRuntime.jsx(
1236
+ "button",
1237
+ {
1238
+ type: "button",
1239
+ onClick: onRemove,
1240
+ "aria-label": "Remove",
1241
+ className: "text-text-dim hover:text-text px-[2px] leading-none",
1242
+ children: "\xD7"
1243
+ }
1244
+ )
1245
+ ]
1246
+ }
1247
+ );
1248
+ });
1249
+ Tag.displayName = "Tag";
1250
+ var ContextMenuRoot = RadixContext__namespace.Root;
1251
+ var ContextMenuTrigger = RadixContext__namespace.Trigger;
1252
+ var ContextMenuPortal = RadixContext__namespace.Portal;
1253
+ var ContextMenuContent = react.forwardRef(
1254
+ function ContextMenuContent2({ className, ...props }, ref) {
1255
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixContext__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1256
+ RadixContext__namespace.Content,
1257
+ {
1258
+ ref,
1259
+ className: cn(
1260
+ "bg-panel border-border-strong z-40 min-w-[180px] rounded-md border p-1 shadow-lg outline-none",
1261
+ "data-[state=open]:animate-[ship-pop-in_140ms_var(--easing-out)]",
1262
+ className
1263
+ ),
1264
+ ...props
1265
+ }
1266
+ ) });
1267
+ }
1268
+ );
1269
+ ContextMenuContent.displayName = "ContextMenuContent";
1270
+ var itemBase = cn(
1271
+ "flex items-center gap-2 px-[10px] py-[6px] rounded-sm text-[12px] cursor-pointer outline-none",
1272
+ "data-[highlighted]:bg-panel-2",
1273
+ "data-[disabled]:opacity-40 data-[disabled]:cursor-not-allowed"
1274
+ );
1275
+ var ContextMenuItem = react.forwardRef(
1276
+ function ContextMenuItem2({ icon, trailing, destructive, className, children, ...props }, ref) {
1277
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1278
+ RadixContext__namespace.Item,
1279
+ {
1280
+ ref,
1281
+ className: cn(itemBase, destructive ? "text-err" : "text-text", className),
1282
+ ...props,
1283
+ children: [
1284
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[14px] text-[12px] opacity-70", children: icon }),
1285
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children }),
1286
+ trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim font-mono text-[10px]", children: trailing })
1287
+ ]
1288
+ }
1289
+ );
1290
+ }
1291
+ );
1292
+ ContextMenuItem.displayName = "ContextMenuItem";
1293
+ var ContextMenuSeparator = react.forwardRef(function ContextMenuSeparator2({ className, ...props }, ref) {
1294
+ return /* @__PURE__ */ jsxRuntime.jsx(
1295
+ RadixContext__namespace.Separator,
1296
+ {
1297
+ ref,
1298
+ className: cn("bg-border my-1 h-[1px]", className),
1299
+ ...props
1300
+ }
1301
+ );
1302
+ });
1303
+ ContextMenuSeparator.displayName = "ContextMenuSeparator";
1304
+ var ContextMenu = RadixContext__namespace.Root;
1305
+ var DialogRoot = RadixDialog__namespace.Root;
1306
+ var DialogTrigger = RadixDialog__namespace.Trigger;
1307
+ var DialogClose = RadixDialog__namespace.Close;
1308
+ var DialogPortal = RadixDialog__namespace.Portal;
1309
+ var DialogOverlay = react.forwardRef(
1310
+ function DialogOverlay2({ className, ...props }, ref) {
1311
+ return /* @__PURE__ */ jsxRuntime.jsx(
1312
+ RadixDialog__namespace.Overlay,
1313
+ {
1314
+ ref,
1315
+ className: cn(
1316
+ "fixed inset-0 z-50 bg-black/55 backdrop-blur-[4px]",
1317
+ "data-[state=open]:animate-[ship-fade-in_150ms_ease]",
1318
+ className
1319
+ ),
1320
+ ...props
1321
+ }
1322
+ );
1323
+ }
1324
+ );
1325
+ DialogOverlay.displayName = "DialogOverlay";
1326
+ var DialogContent = react.forwardRef(function DialogContent2({ className, width = 460, style, children, ...props }, ref) {
1327
+ return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
1328
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1329
+ /* @__PURE__ */ jsxRuntime.jsx(
1330
+ RadixDialog__namespace.Content,
1331
+ {
1332
+ ref,
1333
+ className: cn(
1334
+ "fixed top-1/2 left-1/2 z-[51] w-[calc(100%-40px)] -translate-x-1/2 -translate-y-1/2 p-6",
1335
+ "bg-panel border-border-strong rounded-lg border shadow-lg",
1336
+ "data-[state=open]:animate-[ship-dialog-in_180ms_var(--easing-out)]",
1337
+ "outline-none",
1338
+ className
1339
+ ),
1340
+ style: { maxWidth: width, ...style },
1341
+ ...props,
1342
+ children
1343
+ }
1344
+ )
1345
+ ] });
1346
+ });
1347
+ DialogContent.displayName = "DialogContent";
1348
+ function Dialog({ title, description, footer, width, children, ...rootProps }) {
1349
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogRoot, { ...rootProps, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { width, children: [
1350
+ title && /* @__PURE__ */ jsxRuntime.jsx(
1351
+ RadixDialog__namespace.Title,
1352
+ {
1353
+ className: cn("text-[16px] font-medium", description ? "mb-[6px]" : "mb-4"),
1354
+ children: title
1355
+ }
1356
+ ),
1357
+ description && /* @__PURE__ */ jsxRuntime.jsx(RadixDialog__namespace.Description, { className: "text-text-muted mb-[18px] text-[13px] leading-[1.55]", children: description }),
1358
+ children,
1359
+ footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-5 flex justify-end gap-2", children: footer })
1360
+ ] }) });
1361
+ }
1362
+ var sideClasses = {
1363
+ left: "left-0 border-r border-border-strong data-[state=open]:animate-[ship-slide-in-left_220ms_var(--easing-out)]",
1364
+ right: "right-0 border-l border-border-strong data-[state=open]:animate-[ship-slide-in-right_220ms_var(--easing-out)]"
1365
+ };
1366
+ var DrawerHeader = ({ title, onClose }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border flex items-center justify-between border-b p-[16px] px-5", children: [
1367
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[14px] font-medium", children: title }),
1368
+ /* @__PURE__ */ jsxRuntime.jsx(
1369
+ RadixDialog__namespace.Close,
1370
+ {
1371
+ onClick: onClose,
1372
+ "aria-label": "Close",
1373
+ className: "text-text-dim hover:text-text p-1 text-[18px] leading-none",
1374
+ children: "\xD7"
1375
+ }
1376
+ )
1377
+ ] });
1378
+ var Drawer = react.forwardRef(function Drawer2({ side = "right", title, width = 420, children, ...rootProps }, ref) {
1379
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogRoot, { ...rootProps, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
1380
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1381
+ /* @__PURE__ */ jsxRuntime.jsxs(
1382
+ RadixDialog__namespace.Content,
1383
+ {
1384
+ ref,
1385
+ className: cn(
1386
+ "bg-panel fixed top-0 bottom-0 z-[51] flex flex-col shadow-lg outline-none",
1387
+ sideClasses[side]
1388
+ ),
1389
+ style: { width },
1390
+ children: [
1391
+ title && /* @__PURE__ */ jsxRuntime.jsx(DrawerHeader, { title }),
1392
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto p-5", children })
1393
+ ]
1394
+ }
1395
+ )
1396
+ ] }) });
1397
+ });
1398
+ Drawer.displayName = "Drawer";
1399
+ var Sheet = react.forwardRef(function Sheet2({ title, width = "min(640px, 90vw)", children, ...rootProps }, ref) {
1400
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogRoot, { ...rootProps, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
1401
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1402
+ /* @__PURE__ */ jsxRuntime.jsxs(
1403
+ RadixDialog__namespace.Content,
1404
+ {
1405
+ ref,
1406
+ className: cn(
1407
+ "fixed bottom-0 left-1/2 z-[51] -translate-x-1/2 p-5",
1408
+ "bg-panel border-border-strong rounded-tl-lg rounded-tr-lg border-t shadow-lg outline-none",
1409
+ "data-[state=open]:animate-[ship-slide-in-bottom_220ms_var(--easing-out)]"
1410
+ ),
1411
+ style: { width },
1412
+ children: [
1413
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-border mx-auto mb-[14px] h-1 w-9 rounded-full", "aria-hidden": true }),
1414
+ title && /* @__PURE__ */ jsxRuntime.jsx(RadixDialog__namespace.Title, { className: "mb-1 text-[15px] font-medium", children: title }),
1415
+ children
1416
+ ]
1417
+ }
1418
+ )
1419
+ ] }) });
1420
+ });
1421
+ Sheet.displayName = "Sheet";
1422
+ var AlertDialogRoot = RadixAlert__namespace.Root;
1423
+ var AlertDialogTrigger = RadixAlert__namespace.Trigger;
1424
+ var AlertDialogAction = RadixAlert__namespace.Action;
1425
+ var AlertDialogCancel = RadixAlert__namespace.Cancel;
1426
+ var AlertDialog = react.forwardRef(function AlertDialog2({ title, description, footer, width = 460, children, ...rootProps }, ref) {
1427
+ return /* @__PURE__ */ jsxRuntime.jsx(AlertDialogRoot, { ...rootProps, children: /* @__PURE__ */ jsxRuntime.jsxs(RadixAlert__namespace.Portal, { children: [
1428
+ /* @__PURE__ */ jsxRuntime.jsx(
1429
+ RadixAlert__namespace.Overlay,
1430
+ {
1431
+ className: cn(
1432
+ "fixed inset-0 z-50 bg-black/55 backdrop-blur-[4px]",
1433
+ "data-[state=open]:animate-[ship-fade-in_150ms_ease]"
1434
+ )
1435
+ }
1436
+ ),
1437
+ /* @__PURE__ */ jsxRuntime.jsxs(
1438
+ RadixAlert__namespace.Content,
1439
+ {
1440
+ ref,
1441
+ style: { maxWidth: width },
1442
+ className: cn(
1443
+ "fixed top-1/2 left-1/2 z-[51] w-[calc(100%-40px)] -translate-x-1/2 -translate-y-1/2 p-6",
1444
+ "bg-panel border-border-strong rounded-lg border shadow-lg outline-none",
1445
+ "data-[state=open]:animate-[ship-dialog-in_180ms_var(--easing-out)]"
1446
+ ),
1447
+ children: [
1448
+ /* @__PURE__ */ jsxRuntime.jsx(
1449
+ RadixAlert__namespace.Title,
1450
+ {
1451
+ className: cn("text-[16px] font-medium", description ? "mb-[6px]" : "mb-4"),
1452
+ children: title
1453
+ }
1454
+ ),
1455
+ description && /* @__PURE__ */ jsxRuntime.jsx(RadixAlert__namespace.Description, { className: "text-text-muted mb-[18px] text-[13px] leading-[1.55]", children: description }),
1456
+ children,
1457
+ footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-5 flex justify-end gap-2", children: footer })
1458
+ ]
1459
+ }
1460
+ )
1461
+ ] }) });
1462
+ });
1463
+ AlertDialog.displayName = "AlertDialog";
1464
+ var DropdownMenuRoot = RadixMenu__namespace.Root;
1465
+ var DropdownMenuTrigger = RadixMenu__namespace.Trigger;
1466
+ var DropdownMenuPortal = RadixMenu__namespace.Portal;
1467
+ var DropdownMenuGroup = RadixMenu__namespace.Group;
1468
+ var DropdownMenuLabel = RadixMenu__namespace.Label;
1469
+ var DropdownMenuRadioGroup = RadixMenu__namespace.RadioGroup;
1470
+ var DropdownMenuContent = react.forwardRef(
1471
+ function DropdownMenuContent2({ className, sideOffset = 6, align = "start", ...props }, ref) {
1472
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixMenu__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1473
+ RadixMenu__namespace.Content,
1474
+ {
1475
+ ref,
1476
+ sideOffset,
1477
+ align,
1478
+ className: cn(
1479
+ "bg-panel border-border-strong z-40 min-w-[180px] rounded-md border p-1 shadow-lg outline-none",
1480
+ "data-[state=open]:animate-[ship-pop-in_140ms_var(--easing-out)]",
1481
+ className
1482
+ ),
1483
+ ...props
1484
+ }
1485
+ ) });
1486
+ }
1487
+ );
1488
+ DropdownMenuContent.displayName = "DropdownMenuContent";
1489
+ var itemBase2 = cn(
1490
+ "flex items-center gap-2 px-[10px] py-[6px] rounded-sm text-[12px] cursor-pointer outline-none",
1491
+ "data-[highlighted]:bg-panel-2",
1492
+ "data-[disabled]:opacity-40 data-[disabled]:cursor-not-allowed"
1493
+ );
1494
+ var MenuItem = react.forwardRef(function MenuItem2({ icon, trailing, destructive, className, children, ...props }, ref) {
1495
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1496
+ RadixMenu__namespace.Item,
1497
+ {
1498
+ ref,
1499
+ className: cn(itemBase2, destructive ? "text-err" : "text-text", className),
1500
+ ...props,
1501
+ children: [
1502
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[14px] text-[12px] opacity-70", children: icon }),
1503
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children }),
1504
+ trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim font-mono text-[10px]", children: trailing })
1505
+ ]
1506
+ }
1507
+ );
1508
+ });
1509
+ MenuItem.displayName = "MenuItem";
1510
+ var MenuCheckboxItem = react.forwardRef(
1511
+ function MenuCheckboxItem2({ className, children, ...props }, ref) {
1512
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1513
+ RadixMenu__namespace.CheckboxItem,
1514
+ {
1515
+ ref,
1516
+ className: cn(itemBase2, "text-text relative pl-[26px]", className),
1517
+ ...props,
1518
+ children: [
1519
+ /* @__PURE__ */ jsxRuntime.jsx(RadixMenu__namespace.ItemIndicator, { className: "text-accent absolute top-1/2 left-2 -translate-y-1/2 text-[10px]", children: "\u2713" }),
1520
+ children
1521
+ ]
1522
+ }
1523
+ );
1524
+ }
1525
+ );
1526
+ MenuCheckboxItem.displayName = "MenuCheckboxItem";
1527
+ var MenuSeparator = react.forwardRef(
1528
+ function MenuSeparator2({ className, ...props }, ref) {
1529
+ return /* @__PURE__ */ jsxRuntime.jsx(
1530
+ RadixMenu__namespace.Separator,
1531
+ {
1532
+ ref,
1533
+ className: cn("bg-border my-1 h-[1px]", className),
1534
+ ...props
1535
+ }
1536
+ );
1537
+ }
1538
+ );
1539
+ MenuSeparator.displayName = "MenuSeparator";
1540
+ var DropdownMenu = RadixMenu__namespace.Root;
1541
+ var HoverCardRoot = RadixHoverCard__namespace.Root;
1542
+ var HoverCardTrigger = RadixHoverCard__namespace.Trigger;
1543
+ var HoverCardPortal = RadixHoverCard__namespace.Portal;
1544
+ var HoverCardContent = react.forwardRef(
1545
+ function HoverCardContent2({ className, sideOffset = 4, ...props }, ref) {
1546
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixHoverCard__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1547
+ RadixHoverCard__namespace.Content,
1548
+ {
1549
+ ref,
1550
+ sideOffset,
1551
+ className: cn(
1552
+ "rounded-base bg-panel border-border-strong z-40 border p-[14px] shadow-lg outline-none",
1553
+ "data-[state=open]:animate-[ship-pop-in_140ms_var(--easing-out)]",
1554
+ className
1555
+ ),
1556
+ ...props
1557
+ }
1558
+ ) });
1559
+ }
1560
+ );
1561
+ HoverCardContent.displayName = "HoverCardContent";
1562
+ function HoverCard({ trigger, content, ...rootProps }) {
1563
+ return /* @__PURE__ */ jsxRuntime.jsxs(RadixHoverCard__namespace.Root, { openDelay: 200, closeDelay: 120, ...rootProps, children: [
1564
+ /* @__PURE__ */ jsxRuntime.jsx(RadixHoverCard__namespace.Trigger, { asChild: true, children: trigger }),
1565
+ /* @__PURE__ */ jsxRuntime.jsx(HoverCardContent, { children: content })
1566
+ ] });
1567
+ }
1568
+ var PopoverRoot = RadixPopover__namespace.Root;
1569
+ var PopoverTrigger = RadixPopover__namespace.Trigger;
1570
+ var PopoverAnchor = RadixPopover__namespace.Anchor;
1571
+ var PopoverPortal = RadixPopover__namespace.Portal;
1572
+ var PopoverClose = RadixPopover__namespace.Close;
1573
+ var PopoverArrow = RadixPopover__namespace.Arrow;
1574
+ var PopoverContent = react.forwardRef(
1575
+ function PopoverContent2({ className, align = "start", sideOffset = 6, ...props }, ref) {
1576
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixPopover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1577
+ RadixPopover__namespace.Content,
1578
+ {
1579
+ ref,
1580
+ align,
1581
+ sideOffset,
1582
+ className: cn(
1583
+ "bg-panel border-border-strong z-40 rounded-md border p-[6px] shadow-lg outline-none",
1584
+ "data-[state=open]:animate-[ship-pop-in_140ms_var(--easing-out)]",
1585
+ className
1586
+ ),
1587
+ ...props
1588
+ }
1589
+ ) });
1590
+ }
1591
+ );
1592
+ PopoverContent.displayName = "PopoverContent";
1593
+ var Popover = RadixPopover__namespace.Root;
1594
+ var ToastContext = react.createContext(null);
1595
+ var variantIcon = {
1596
+ default: "\u25CF",
1597
+ info: "\u2139",
1598
+ ok: "\u2713",
1599
+ warn: "!",
1600
+ err: "\xD7"
1601
+ };
1602
+ var variantTextColor = {
1603
+ default: "text-text-dim",
1604
+ info: "text-accent",
1605
+ ok: "text-ok",
1606
+ warn: "text-warn",
1607
+ err: "text-err"
1608
+ };
1609
+ var variantBorderLeft = {
1610
+ default: "border-l-border",
1611
+ info: "border-l-accent",
1612
+ ok: "border-l-ok",
1613
+ warn: "border-l-warn",
1614
+ err: "border-l-err"
1615
+ };
1616
+ function ToastProvider({ children }) {
1617
+ const [toasts, setToasts] = react.useState([]);
1618
+ const toast = react.useCallback((t) => {
1619
+ const id = t.id ?? Math.random().toString(36).slice(2);
1620
+ setToasts((prev) => [...prev, { ...t, id }]);
1621
+ return id;
1622
+ }, []);
1623
+ const dismiss = react.useCallback((id) => {
1624
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1625
+ }, []);
1626
+ const value = react.useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
1627
+ return /* @__PURE__ */ jsxRuntime.jsx(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsxs(RadixToast__namespace.Provider, { swipeDirection: "right", children: [
1628
+ children,
1629
+ toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ToastCard, { toast: t, onDismiss: () => dismiss(t.id) }, t.id)),
1630
+ /* @__PURE__ */ jsxRuntime.jsx(RadixToast__namespace.Viewport, { className: "fixed right-5 bottom-5 z-[70] flex w-[380px] max-w-[calc(100vw-40px)] flex-col gap-2 outline-none" })
1631
+ ] }) });
1632
+ }
1633
+ function useToast() {
1634
+ const ctx = react.useContext(ToastContext);
1635
+ if (!ctx) throw new Error("useToast must be inside <ToastProvider>");
1636
+ return ctx;
1637
+ }
1638
+ var ToastCard = react.forwardRef(function ToastCard2({ toast, onDismiss }, ref) {
1639
+ const variant = toast.variant ?? "default";
1640
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1641
+ RadixToast__namespace.Root,
1642
+ {
1643
+ ref,
1644
+ duration: toast.duration ?? 4e3,
1645
+ onOpenChange: (open) => {
1646
+ if (!open) onDismiss();
1647
+ },
1648
+ className: cn(
1649
+ "bg-panel border-border pointer-events-auto rounded-md border border-l-[2px] p-3 shadow-lg",
1650
+ "flex items-start gap-[10px]",
1651
+ "data-[state=open]:animate-[ship-toast-in_220ms_var(--easing-out)]",
1652
+ variantBorderLeft[variant]
1653
+ ),
1654
+ children: [
1655
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("mt-px text-[14px] leading-none", variantTextColor[variant]), children: variantIcon[variant] }),
1656
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
1657
+ /* @__PURE__ */ jsxRuntime.jsx(RadixToast__namespace.Title, { className: "text-text text-[13px] font-medium", children: toast.title }),
1658
+ toast.description && /* @__PURE__ */ jsxRuntime.jsx(RadixToast__namespace.Description, { className: "text-text-muted mt-[2px] text-[12px] leading-[1.5]", children: toast.description }),
1659
+ toast.action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: toast.action })
1660
+ ] }),
1661
+ /* @__PURE__ */ jsxRuntime.jsx(
1662
+ RadixToast__namespace.Close,
1663
+ {
1664
+ "aria-label": "Dismiss",
1665
+ className: "text-text-dim hover:text-text -mt-px text-[15px] leading-none",
1666
+ children: "\xD7"
1667
+ }
1668
+ )
1669
+ ]
1670
+ }
1671
+ );
1672
+ });
1673
+ ToastCard.displayName = "ToastCard";
1674
+ var TooltipProvider = RadixTooltip__namespace.Provider;
1675
+ var TooltipRoot = RadixTooltip__namespace.Root;
1676
+ var TooltipTrigger = RadixTooltip__namespace.Trigger;
1677
+ var TooltipPortal = RadixTooltip__namespace.Portal;
1678
+ var TooltipArrow = RadixTooltip__namespace.Arrow;
1679
+ var TooltipContent = react.forwardRef(
1680
+ function TooltipContent2({ className, sideOffset = 6, ...props }, ref) {
1681
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixTooltip__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1682
+ RadixTooltip__namespace.Content,
1683
+ {
1684
+ ref,
1685
+ sideOffset,
1686
+ className: cn(
1687
+ "pointer-events-none z-[60] rounded-sm px-2 py-[5px] text-[11px] whitespace-nowrap",
1688
+ "bg-text text-bg",
1689
+ "data-[state=delayed-open]:animate-[ship-pop-in_120ms_var(--easing-out)]",
1690
+ className
1691
+ ),
1692
+ ...props
1693
+ }
1694
+ ) });
1695
+ }
1696
+ );
1697
+ TooltipContent.displayName = "TooltipContent";
1698
+ function Tooltip({ content, children, side = "top", delayDuration = 400 }) {
1699
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration, children: /* @__PURE__ */ jsxRuntime.jsxs(TooltipRoot, { children: [
1700
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children }),
1701
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side, children: content })
1702
+ ] }) });
1703
+ }
1704
+ var alertStyles = classVarianceAuthority.cva("flex items-start gap-3 rounded-base border bg-panel p-3 text-[13px]", {
1705
+ variants: {
1706
+ variant: {
1707
+ info: "border-border border-l-2 border-l-accent",
1708
+ ok: "border-border border-l-2 border-l-ok",
1709
+ warn: "border-border border-l-2 border-l-warn",
1710
+ err: "border-border border-l-2 border-l-err"
1711
+ }
1712
+ },
1713
+ defaultVariants: { variant: "info" }
1714
+ });
1715
+ var iconColorClass = {
1716
+ info: "text-accent",
1717
+ ok: "text-ok",
1718
+ warn: "text-warn",
1719
+ err: "text-err"
1720
+ };
1721
+ var defaultGlyph = {
1722
+ info: "\u2139",
1723
+ ok: "\u2713",
1724
+ warn: "!",
1725
+ err: "\xD7"
1726
+ };
1727
+ var Alert = react.forwardRef(function Alert2({ variant = "info", title, description, icon, action, className, children, ...props }, ref) {
1728
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1729
+ "div",
1730
+ {
1731
+ ref,
1732
+ role: variant === "err" || variant === "warn" ? "alert" : "status",
1733
+ className: cn(alertStyles({ variant }), className),
1734
+ ...props,
1735
+ children: [
1736
+ /* @__PURE__ */ jsxRuntime.jsx(
1737
+ "span",
1738
+ {
1739
+ "aria-hidden": true,
1740
+ className: cn("mt-[1px] text-[14px] leading-none", iconColorClass[variant]),
1741
+ children: icon ?? defaultGlyph[variant]
1742
+ }
1743
+ ),
1744
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
1745
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: title }),
1746
+ description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-muted mt-[2px] text-[12px]", children: description }),
1747
+ children
1748
+ ] }),
1749
+ action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-1 shrink-0", children: action })
1750
+ ]
1751
+ }
1752
+ );
1753
+ });
1754
+ Alert.displayName = "Alert";
1755
+ var bannerStyles = classVarianceAuthority.cva(
1756
+ "flex items-center gap-[10px] border-b border-border px-[14px] py-2 text-[12px]",
1757
+ {
1758
+ variants: {
1759
+ variant: {
1760
+ info: "bg-[color-mix(in_oklab,var(--color-accent),transparent_82%)] text-accent",
1761
+ ok: "bg-[color-mix(in_oklab,var(--color-ok),transparent_82%)] text-ok",
1762
+ warn: "bg-[color-mix(in_oklab,var(--color-warn),transparent_82%)] text-warn",
1763
+ err: "bg-[color-mix(in_oklab,var(--color-err),transparent_82%)] text-err"
1764
+ },
1765
+ sticky: {
1766
+ true: "sticky top-0 z-30",
1767
+ false: ""
1768
+ }
1769
+ },
1770
+ defaultVariants: { variant: "info", sticky: false }
1771
+ }
1772
+ );
1773
+ var defaultGlyph2 = {
1774
+ info: "\u2726",
1775
+ ok: "\u2713",
1776
+ warn: "!",
1777
+ err: "\xD7"
1778
+ };
1779
+ var Banner = react.forwardRef(function Banner2({ variant = "info", sticky, icon, action, className, children, ...props }, ref) {
1780
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1781
+ "div",
1782
+ {
1783
+ ref,
1784
+ role: variant === "err" || variant === "warn" ? "alert" : "status",
1785
+ className: cn(bannerStyles({ variant, sticky }), className),
1786
+ ...props,
1787
+ children: [
1788
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "leading-none", children: icon ?? defaultGlyph2[variant] }),
1789
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children }),
1790
+ action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto", children: action })
1791
+ ]
1792
+ }
1793
+ );
1794
+ });
1795
+ Banner.displayName = "Banner";
1796
+ var Breadcrumbs = react.forwardRef(function Breadcrumbs2({ separator = "/", className, children, ...props }, ref) {
1797
+ const crumbs = react.Children.toArray(children).filter(react.isValidElement);
1798
+ const last = crumbs.length - 1;
1799
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { ref, "aria-label": "Breadcrumb", className: cn("text-[13px]", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "text-text-muted flex flex-wrap items-center gap-[6px]", children: crumbs.map((crumb, i) => {
1800
+ const isCurrent = i === last;
1801
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "inline-flex items-center gap-[6px]", children: [
1802
+ isCurrent ? /* @__PURE__ */ jsxRuntime.jsx(Crumb, { ...crumb.props, current: true }) : crumb,
1803
+ !isCurrent && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-text-dim", children: separator })
1804
+ ] }, i);
1805
+ }) }) });
1806
+ });
1807
+ Breadcrumbs.displayName = "Breadcrumbs";
1808
+ var Crumb = react.forwardRef(function Crumb2({ current, className, href, children, ...props }, ref) {
1809
+ if (current) {
1810
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-current": "page", className: cn("text-text", className), children });
1811
+ }
1812
+ return /* @__PURE__ */ jsxRuntime.jsx(
1813
+ "a",
1814
+ {
1815
+ ref,
1816
+ href: href ?? "#",
1817
+ className: cn("hover:text-text transition-colors duration-(--duration-micro)", className),
1818
+ ...props,
1819
+ children
1820
+ }
1821
+ );
1822
+ });
1823
+ Crumb.displayName = "Crumb";
1824
+ function normalize(option) {
1825
+ if (typeof option === "string") {
1826
+ return { value: option, label: option, searchText: option.toLowerCase() };
1827
+ }
1828
+ const labelString = typeof option.label === "string" ? option.label : typeof option.label === "undefined" ? option.value : "";
1829
+ const descriptionString = typeof option.description === "string" ? option.description : "";
1830
+ return {
1831
+ value: option.value,
1832
+ label: option.label ?? option.value,
1833
+ description: option.description,
1834
+ searchText: `${labelString} ${descriptionString}`.toLowerCase(),
1835
+ disabled: option.disabled
1836
+ };
1837
+ }
1838
+ var defaultFilter = (option, query) => option.searchText.includes(query.toLowerCase());
1839
+ var Combobox = react.forwardRef(function Combobox2({
1840
+ options,
1841
+ value: valueProp,
1842
+ defaultValue,
1843
+ onValueChange,
1844
+ query: queryProp,
1845
+ defaultQuery,
1846
+ onQueryChange,
1847
+ placeholder,
1848
+ filter = defaultFilter,
1849
+ emptyState,
1850
+ width = 260,
1851
+ disabled,
1852
+ name,
1853
+ id,
1854
+ "aria-label": ariaLabel
1855
+ }, ref) {
1856
+ const reactId = react.useId();
1857
+ const listboxId = `${id ?? reactId}-listbox`;
1858
+ const inputId = id ?? `${reactId}-input`;
1859
+ const normalized = react.useMemo(() => options.map(normalize), [options]);
1860
+ const [value, setValue] = useControllableState({
1861
+ value: valueProp,
1862
+ defaultValue,
1863
+ onChange: onValueChange
1864
+ });
1865
+ const initialQuery = react.useMemo(() => {
1866
+ if (defaultQuery !== void 0) return defaultQuery;
1867
+ if (defaultValue !== void 0) {
1868
+ const opt = normalized.find((o) => o.value === defaultValue);
1869
+ if (opt && typeof opt.label === "string") return opt.label;
1870
+ }
1871
+ return "";
1872
+ }, [defaultQuery, defaultValue, normalized]);
1873
+ const [query, setQuery] = useControllableState({
1874
+ value: queryProp,
1875
+ defaultValue: initialQuery,
1876
+ onChange: onQueryChange
1877
+ });
1878
+ const [open, setOpen] = react.useState(false);
1879
+ const wrapperRef = react.useRef(null);
1880
+ useOutsideClick(wrapperRef, () => setOpen(false));
1881
+ const filtered = react.useMemo(
1882
+ () => query ? normalized.filter((o) => filter(o, query)) : normalized,
1883
+ [normalized, query, filter]
1884
+ );
1885
+ const { cursor, setCursor, onKeyDown } = useKeyboardList({
1886
+ count: filtered.length,
1887
+ defaultCursor: 0,
1888
+ onSelect: (i) => {
1889
+ const item = filtered[i];
1890
+ if (item && !item.disabled) commit(item);
1891
+ }
1892
+ });
1893
+ react.useEffect(() => {
1894
+ setCursor(0);
1895
+ }, [query, setCursor]);
1896
+ function commit(option) {
1897
+ setValue(option.value);
1898
+ if (typeof option.label === "string") setQuery(option.label);
1899
+ setOpen(false);
1900
+ }
1901
+ const handleKey = (event) => {
1902
+ if (event.key === "Escape") {
1903
+ setOpen(false);
1904
+ return;
1905
+ }
1906
+ if (!open && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
1907
+ setOpen(true);
1908
+ }
1909
+ onKeyDown(event);
1910
+ };
1911
+ const handleBlur = (event) => {
1912
+ if (wrapperRef.current && !wrapperRef.current.contains(event.relatedTarget)) {
1913
+ setOpen(false);
1914
+ }
1915
+ };
1916
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapperRef, className: "relative", style: { width }, children: [
1917
+ /* @__PURE__ */ jsxRuntime.jsx(
1918
+ "input",
1919
+ {
1920
+ ref,
1921
+ id: inputId,
1922
+ name,
1923
+ type: "text",
1924
+ role: "combobox",
1925
+ autoComplete: "off",
1926
+ "aria-autocomplete": "list",
1927
+ "aria-expanded": open,
1928
+ "aria-controls": listboxId,
1929
+ "aria-activedescendant": open && filtered.length > 0 ? `${listboxId}-option-${cursor}` : void 0,
1930
+ "aria-label": ariaLabel,
1931
+ disabled,
1932
+ placeholder,
1933
+ value: query ?? "",
1934
+ onChange: (e) => {
1935
+ setQuery(e.target.value);
1936
+ setOpen(true);
1937
+ if (value !== void 0) setValue("");
1938
+ },
1939
+ onFocus: () => setOpen(true),
1940
+ onBlur: handleBlur,
1941
+ onKeyDown: handleKey,
1942
+ className: cn(
1943
+ "border-border bg-panel text-text block w-full rounded-md border px-3 py-2 text-[13px] outline-none",
1944
+ "transition-[border,box-shadow] duration-(--duration-micro)",
1945
+ "placeholder:text-text-dim",
1946
+ "focus-visible:border-accent focus-visible:ring-accent-dim focus-visible:ring-[3px]",
1947
+ "disabled:cursor-not-allowed disabled:opacity-40"
1948
+ )
1949
+ }
1950
+ ),
1951
+ open && /* @__PURE__ */ jsxRuntime.jsx(
1952
+ "ul",
1953
+ {
1954
+ id: listboxId,
1955
+ role: "listbox",
1956
+ "aria-label": ariaLabel ?? "Suggestions",
1957
+ className: cn(
1958
+ "absolute top-full right-0 left-0 z-30 mt-1 max-h-[220px] overflow-auto",
1959
+ "border-border bg-panel rounded-md border p-1 shadow-lg"
1960
+ ),
1961
+ children: filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-text-dim px-2 py-3 text-center text-[12px]", role: "presentation", children: emptyState ?? "No matches" }) : filtered.map((option, i) => {
1962
+ const isActive = i === cursor;
1963
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1964
+ "li",
1965
+ {
1966
+ id: `${listboxId}-option-${i}`,
1967
+ role: "option",
1968
+ "aria-selected": isActive,
1969
+ "aria-disabled": option.disabled || void 0,
1970
+ onMouseEnter: () => setCursor(i),
1971
+ onMouseDown: (e) => {
1972
+ e.preventDefault();
1973
+ if (!option.disabled) commit(option);
1974
+ },
1975
+ className: cn(
1976
+ "text-text cursor-pointer rounded-sm px-[10px] py-2 text-[12px]",
1977
+ isActive && "bg-accent-dim text-accent",
1978
+ option.disabled && "pointer-events-none opacity-40"
1979
+ ),
1980
+ children: [
1981
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: option.label }),
1982
+ option.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-dim text-[11px]", children: option.description })
1983
+ ]
1984
+ },
1985
+ option.value
1986
+ );
1987
+ })
1988
+ }
1989
+ ),
1990
+ name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: value ?? "", readOnly: true })
1991
+ ] });
1992
+ });
1993
+ Combobox.displayName = "Combobox";
1994
+ function flatItems(groups) {
1995
+ return groups.flatMap((g) => g.items);
1996
+ }
1997
+ var CommandPalette = react.forwardRef(
1998
+ function CommandPalette2({
1999
+ open,
2000
+ onOpenChange,
2001
+ query,
2002
+ onQueryChange,
2003
+ groups,
2004
+ onSelect,
2005
+ placeholder = "Search\u2026",
2006
+ footer,
2007
+ emptyState,
2008
+ width = 540
2009
+ }, ref) {
2010
+ const flat = react.useMemo(() => flatItems(groups), [groups]);
2011
+ const { cursor, setCursor, onKeyDown } = useKeyboardList({
2012
+ count: flat.length,
2013
+ defaultCursor: 0,
2014
+ onSelect: (i) => {
2015
+ const item = flat[i];
2016
+ if (item) onSelect(item.id);
2017
+ }
2018
+ });
2019
+ react.useEffect(() => {
2020
+ setCursor(0);
2021
+ }, [query, groups, setCursor]);
2022
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixDialog__namespace.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(RadixDialog__namespace.Portal, { children: [
2023
+ /* @__PURE__ */ jsxRuntime.jsx(
2024
+ RadixDialog__namespace.Overlay,
2025
+ {
2026
+ className: cn(
2027
+ "fixed inset-0 z-50 bg-black/55 backdrop-blur-[4px]",
2028
+ "data-[state=open]:animate-[ship-fade-in_150ms_ease]"
2029
+ )
2030
+ }
2031
+ ),
2032
+ /* @__PURE__ */ jsxRuntime.jsxs(
2033
+ RadixDialog__namespace.Content,
2034
+ {
2035
+ ref,
2036
+ "aria-label": "Command palette",
2037
+ "aria-describedby": void 0,
2038
+ style: { width },
2039
+ className: cn(
2040
+ "fixed top-[20%] left-1/2 z-[51] max-w-[calc(100%-40px)] -translate-x-1/2",
2041
+ "border-border-strong bg-panel overflow-hidden rounded-xl border shadow-lg",
2042
+ "outline-none data-[state=open]:animate-[ship-dialog-in_180ms_var(--easing-out)]"
2043
+ ),
2044
+ onKeyDown,
2045
+ children: [
2046
+ /* @__PURE__ */ jsxRuntime.jsx(RadixDialog__namespace.Title, { className: "sr-only", children: "Command palette" }),
2047
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border flex items-center gap-[10px] border-b px-4 py-[14px]", children: [
2048
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-text-dim", children: "\u2315" }),
2049
+ /* @__PURE__ */ jsxRuntime.jsx(
2050
+ "input",
2051
+ {
2052
+ autoFocus: true,
2053
+ type: "text",
2054
+ value: query,
2055
+ onChange: (e) => onQueryChange(e.target.value),
2056
+ placeholder,
2057
+ "aria-label": "Search",
2058
+ "aria-autocomplete": "list",
2059
+ className: "text-text placeholder:text-text-dim flex-1 border-0 bg-transparent text-[14px] outline-none"
2060
+ }
2061
+ ),
2062
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "border-border text-text-dim rounded-xs border px-[6px] py-[2px] font-mono text-[10px]", children: "ESC" })
2063
+ ] }),
2064
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-[220px] p-2", role: "listbox", "aria-label": "Results", children: flat.length === 0 ? emptyState ?? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-dim px-3 py-5 text-center text-[12px]", children: "No matches" }) : /* @__PURE__ */ jsxRuntime.jsx(
2065
+ CommandGroups,
2066
+ {
2067
+ groups,
2068
+ cursor,
2069
+ setCursor,
2070
+ onSelect
2071
+ }
2072
+ ) }),
2073
+ footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-border text-text-dim flex gap-4 border-t px-[14px] py-[10px] font-mono text-[10px]", children: footer })
2074
+ ]
2075
+ }
2076
+ )
2077
+ ] }) });
2078
+ }
2079
+ );
2080
+ CommandPalette.displayName = "CommandPalette";
2081
+ function CommandGroups({ groups, cursor, setCursor, onSelect }) {
2082
+ let runningIndex = 0;
2083
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: groups.map((group, gIdx) => {
2084
+ if (group.items.length === 0) return null;
2085
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2086
+ group.label && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-text-dim px-2 pt-2 pb-1 font-mono text-[9px] tracking-[1.4px] uppercase", children: [
2087
+ group.label,
2088
+ " \xB7 ",
2089
+ group.items.length
2090
+ ] }),
2091
+ group.items.map((item) => {
2092
+ const myIndex = runningIndex++;
2093
+ const isActive = cursor === myIndex;
2094
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2095
+ "button",
2096
+ {
2097
+ type: "button",
2098
+ role: "option",
2099
+ "aria-selected": isActive,
2100
+ onClick: () => onSelect(item.id),
2101
+ onMouseEnter: () => setCursor(myIndex),
2102
+ className: cn(
2103
+ "flex w-full cursor-pointer items-center gap-[10px] rounded-md border-0 bg-transparent px-[10px] py-2 text-left outline-none",
2104
+ isActive ? "bg-accent-dim text-accent" : "text-text hover:bg-panel-2"
2105
+ ),
2106
+ children: [
2107
+ item.glyph != null && /* @__PURE__ */ jsxRuntime.jsx(
2108
+ "span",
2109
+ {
2110
+ "aria-hidden": true,
2111
+ className: cn(
2112
+ "font-mono text-[12px]",
2113
+ isActive ? "text-accent" : "text-text-muted"
2114
+ ),
2115
+ children: item.glyph
2116
+ }
2117
+ ),
2118
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
2119
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-[13px]", children: item.label }),
2120
+ item.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim block truncate text-[11px]", children: item.description })
2121
+ ] }),
2122
+ item.trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim font-mono text-[10px]", children: item.trailing })
2123
+ ]
2124
+ },
2125
+ item.id
2126
+ );
2127
+ })
2128
+ ] }, gIdx);
2129
+ }) });
2130
+ }
2131
+ function filterCommandItems(query, groups) {
2132
+ const q = query.trim().toLowerCase();
2133
+ if (!q) return groups.map((g) => ({ ...g, items: [...g.items] }));
2134
+ return groups.map((g) => ({
2135
+ ...g,
2136
+ items: g.items.filter((item) => {
2137
+ const haystack = item.searchText ?? `${typeof item.label === "string" ? item.label : ""} ${typeof item.description === "string" ? item.description : ""}`;
2138
+ return haystack.toLowerCase().includes(q);
2139
+ })
2140
+ })).filter((g) => g.items.length > 0);
2141
+ }
2142
+ var alignClass = {
2143
+ left: "text-left",
2144
+ right: "text-right",
2145
+ center: "text-center"
2146
+ };
2147
+ function DataTable(props) {
2148
+ const {
2149
+ data,
2150
+ columns,
2151
+ rowKey,
2152
+ sort: sortProp,
2153
+ defaultSort,
2154
+ onSortChange,
2155
+ selectable,
2156
+ selected: selectedProp,
2157
+ defaultSelected,
2158
+ onSelectionChange,
2159
+ emptyState,
2160
+ stickyHeader,
2161
+ caption,
2162
+ className,
2163
+ ref
2164
+ } = props;
2165
+ const [sort, setSort] = useControllableState({
2166
+ value: sortProp,
2167
+ defaultValue: defaultSort ?? null,
2168
+ onChange: onSortChange
2169
+ });
2170
+ const [selected, setSelected] = useControllableState({
2171
+ value: selectedProp instanceof Set ? selectedProp : selectedProp,
2172
+ defaultValue: new Set(defaultSelected ?? []),
2173
+ onChange: onSelectionChange
2174
+ });
2175
+ const sortableMap = react.useMemo(() => {
2176
+ const m = /* @__PURE__ */ new Map();
2177
+ for (const c of columns) if (c.accessor) m.set(c.key, c);
2178
+ return m;
2179
+ }, [columns]);
2180
+ const sortedData = react.useMemo(() => {
2181
+ if (!sort) return [...data];
2182
+ const col = sortableMap.get(sort.key);
2183
+ if (!col || !col.accessor) return [...data];
2184
+ const factor = sort.direction === "asc" ? 1 : -1;
2185
+ return [...data].sort((a, b) => {
2186
+ const av = col.accessor(a);
2187
+ const bv = col.accessor(b);
2188
+ if (typeof av === "number" && typeof bv === "number") return (av - bv) * factor;
2189
+ return String(av).localeCompare(String(bv)) * factor;
2190
+ });
2191
+ }, [data, sort, sortableMap]);
2192
+ const allIds = react.useMemo(() => sortedData.map(rowKey), [sortedData, rowKey]);
2193
+ const allSelected = allIds.length > 0 && allIds.every((id) => selected.has(id));
2194
+ const someSelected = !allSelected && allIds.some((id) => selected.has(id));
2195
+ const headerCheckRef = react.useRef(null);
2196
+ react.useEffect(() => {
2197
+ if (headerCheckRef.current) headerCheckRef.current.indeterminate = someSelected;
2198
+ }, [someSelected]);
2199
+ const toggleSort = (key) => {
2200
+ const col = sortableMap.get(key);
2201
+ if (!col) return;
2202
+ setSort((prev) => {
2203
+ if (prev?.key !== key) return { key, direction: "asc" };
2204
+ if (prev.direction === "asc") return { key, direction: "desc" };
2205
+ return null;
2206
+ });
2207
+ };
2208
+ const toggleAll = () => {
2209
+ setSelected((prev) => {
2210
+ const next = new Set(prev ?? []);
2211
+ if (allSelected) {
2212
+ for (const id of allIds) next.delete(id);
2213
+ } else {
2214
+ for (const id of allIds) next.add(id);
2215
+ }
2216
+ return next;
2217
+ });
2218
+ };
2219
+ const toggleRow = (id) => {
2220
+ setSelected((prev) => {
2221
+ const next = new Set(prev ?? []);
2222
+ if (next.has(id)) next.delete(id);
2223
+ else next.add(id);
2224
+ return next;
2225
+ });
2226
+ };
2227
+ return /* @__PURE__ */ jsxRuntime.jsxs("table", { ref, className: cn("w-full border-collapse text-[12px]", className), children: [
2228
+ caption && /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }),
2229
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: cn("bg-panel-2", stickyHeader && "sticky top-0 z-10"), children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2230
+ selectable && /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "border-border w-8 border-b px-3 py-2 text-left", children: /* @__PURE__ */ jsxRuntime.jsx(
2231
+ "input",
2232
+ {
2233
+ ref: headerCheckRef,
2234
+ type: "checkbox",
2235
+ "aria-label": "Select all rows",
2236
+ checked: allSelected,
2237
+ onChange: toggleAll,
2238
+ className: "cursor-pointer accent-[var(--color-accent)]"
2239
+ }
2240
+ ) }),
2241
+ columns.map((col) => {
2242
+ const sortable = !!col.accessor;
2243
+ const isSorted = sort?.key === col.key;
2244
+ const ariaSort = !sortable ? void 0 : isSorted ? sort?.direction === "asc" ? "ascending" : "descending" : "none";
2245
+ const align = col.align ?? "left";
2246
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2247
+ "th",
2248
+ {
2249
+ scope: "col",
2250
+ "aria-sort": ariaSort,
2251
+ onClick: sortable ? () => toggleSort(col.key) : void 0,
2252
+ style: col.width != null ? { width: col.width } : void 0,
2253
+ className: cn(
2254
+ "border-border border-b px-3 py-2 font-mono text-[10px] font-medium tracking-[1.4px] uppercase select-none",
2255
+ alignClass[align],
2256
+ sortable && "cursor-pointer",
2257
+ isSorted ? "text-accent" : "text-text-dim"
2258
+ ),
2259
+ children: [
2260
+ col.header,
2261
+ sortable && isSorted && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "ml-1", children: sort?.direction === "asc" ? "\u2191" : "\u2193" })
2262
+ ]
2263
+ },
2264
+ col.key
2265
+ );
2266
+ })
2267
+ ] }) }),
2268
+ /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
2269
+ sortedData.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
2270
+ "td",
2271
+ {
2272
+ colSpan: columns.length + (selectable ? 1 : 0),
2273
+ className: "text-text-dim px-3 py-8 text-center",
2274
+ children: emptyState ?? "No data"
2275
+ }
2276
+ ) }),
2277
+ sortedData.map((row) => {
2278
+ const id = rowKey(row);
2279
+ const isSelected = selected.has(id);
2280
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2281
+ "tr",
2282
+ {
2283
+ "data-state": isSelected ? "selected" : void 0,
2284
+ className: cn(
2285
+ "border-border border-b transition-colors duration-(--duration-micro) last:border-0",
2286
+ isSelected ? "bg-accent-dim/50" : "hover:bg-panel-2"
2287
+ ),
2288
+ children: [
2289
+ selectable && /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-[10px]", children: /* @__PURE__ */ jsxRuntime.jsx(
2290
+ "input",
2291
+ {
2292
+ type: "checkbox",
2293
+ "aria-label": `Select row ${id}`,
2294
+ checked: isSelected,
2295
+ onChange: () => toggleRow(id),
2296
+ className: "cursor-pointer accent-[var(--color-accent)]"
2297
+ }
2298
+ ) }),
2299
+ columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: cn("px-3 py-[10px]", alignClass[col.align ?? "left"]), children: col.cell ? col.cell(row) : col.accessor ? String(col.accessor(row)) : null }, col.key))
2300
+ ]
2301
+ },
2302
+ id
2303
+ );
2304
+ })
2305
+ ] })
2306
+ ] });
2307
+ }
2308
+ var MONTHS = [
2309
+ "Jan",
2310
+ "Feb",
2311
+ "Mar",
2312
+ "April",
2313
+ "May",
2314
+ "June",
2315
+ "July",
2316
+ "Aug",
2317
+ "Sep",
2318
+ "Oct",
2319
+ "Nov",
2320
+ "Dec"
2321
+ ];
2322
+ var DAYS = ["S", "M", "T", "W", "T", "F", "S"];
2323
+ function isSameDay(a, b) {
2324
+ if (!a) return false;
2325
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
2326
+ }
2327
+ var Calendar = react.forwardRef(function Calendar2({
2328
+ selected,
2329
+ defaultSelected,
2330
+ onSelect,
2331
+ month: monthProp,
2332
+ year: yearProp,
2333
+ defaultMonth,
2334
+ defaultYear,
2335
+ onVisibleMonthChange,
2336
+ isDateDisabled,
2337
+ className,
2338
+ ...props
2339
+ }, ref) {
2340
+ const today = /* @__PURE__ */ new Date();
2341
+ const [selectedDate, setSelectedDate] = useControllableState({
2342
+ value: selected,
2343
+ defaultValue: defaultSelected,
2344
+ onChange: onSelect
2345
+ });
2346
+ const initialMonth = defaultMonth ?? defaultSelected?.getMonth() ?? today.getMonth();
2347
+ const initialYear = defaultYear ?? defaultSelected?.getFullYear() ?? today.getFullYear();
2348
+ const [internalMonth, setInternalMonth] = react.useState(initialMonth);
2349
+ const [internalYear, setInternalYear] = react.useState(initialYear);
2350
+ const month = monthProp ?? internalMonth;
2351
+ const year = yearProp ?? internalYear;
2352
+ const isControlled = monthProp !== void 0 && yearProp !== void 0;
2353
+ const setVisible = (m, y) => {
2354
+ if (!isControlled) {
2355
+ setInternalMonth(m);
2356
+ setInternalYear(y);
2357
+ }
2358
+ onVisibleMonthChange?.({ month: m, year: y });
2359
+ };
2360
+ const goPrev = () => {
2361
+ const m = month === 0 ? 11 : month - 1;
2362
+ const y = month === 0 ? year - 1 : year;
2363
+ setVisible(m, y);
2364
+ };
2365
+ const goNext = () => {
2366
+ const m = month === 11 ? 0 : month + 1;
2367
+ const y = month === 11 ? year + 1 : year;
2368
+ setVisible(m, y);
2369
+ };
2370
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
2371
+ const firstDayOfMonth = new Date(year, month, 1).getDay();
2372
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2373
+ "div",
2374
+ {
2375
+ ref,
2376
+ role: "group",
2377
+ "aria-label": `${MONTHS[month]} ${year}`,
2378
+ className: cn(
2379
+ "rounded-base border-border bg-panel w-[280px] border p-4 shadow-lg",
2380
+ className
2381
+ ),
2382
+ ...props,
2383
+ children: [
2384
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex items-center justify-between", children: [
2385
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[13px] font-medium", "aria-live": "polite", children: [
2386
+ MONTHS[month],
2387
+ " ",
2388
+ year
2389
+ ] }),
2390
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1", children: [
2391
+ /* @__PURE__ */ jsxRuntime.jsx(
2392
+ IconButton,
2393
+ {
2394
+ size: "sm",
2395
+ variant: "ghost",
2396
+ icon: "\u2039",
2397
+ "aria-label": "Previous month",
2398
+ onClick: goPrev
2399
+ }
2400
+ ),
2401
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton, { size: "sm", variant: "ghost", icon: "\u203A", "aria-label": "Next month", onClick: goNext })
2402
+ ] })
2403
+ ] }),
2404
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-7 gap-[2px]", children: [
2405
+ DAYS.map((d, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "text-text-dim p-1 text-center font-mono text-[10px]", children: d }, i)),
2406
+ Array.from({ length: firstDayOfMonth }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true }, `pad-${i}`)),
2407
+ Array.from({ length: daysInMonth }).map((_, i) => {
2408
+ const d = i + 1;
2409
+ const date = new Date(year, month, d);
2410
+ const isSelected = isSameDay(selectedDate, date);
2411
+ const isToday = isSameDay(today, date);
2412
+ const disabled = isDateDisabled?.(date) ?? false;
2413
+ return /* @__PURE__ */ jsxRuntime.jsx(
2414
+ "button",
2415
+ {
2416
+ type: "button",
2417
+ disabled,
2418
+ "aria-pressed": isSelected,
2419
+ "aria-current": isToday ? "date" : void 0,
2420
+ "aria-label": date.toDateString(),
2421
+ onClick: () => setSelectedDate(date),
2422
+ className: cn(
2423
+ "cursor-pointer rounded-xs border-0 bg-transparent py-[6px] text-center text-[12px] outline-none",
2424
+ "focus-visible:ring-accent-dim focus-visible:ring-[3px]",
2425
+ "disabled:cursor-not-allowed disabled:opacity-30",
2426
+ !isSelected && !disabled && "text-text hover:bg-panel-2",
2427
+ isSelected && "bg-accent text-on-accent font-semibold",
2428
+ !isSelected && isToday && "border-border-strong border"
2429
+ ),
2430
+ children: d
2431
+ },
2432
+ d
2433
+ );
2434
+ })
2435
+ ] })
2436
+ ]
2437
+ }
2438
+ );
2439
+ });
2440
+ Calendar.displayName = "Calendar";
2441
+ var defaultFormat = (d) => d.toLocaleDateString();
2442
+ var DatePicker = react.forwardRef(function DatePicker2({
2443
+ value: valueProp,
2444
+ defaultValue,
2445
+ onValueChange,
2446
+ placeholder = "Pick a date",
2447
+ format = defaultFormat,
2448
+ isDateDisabled,
2449
+ width = 200,
2450
+ disabled,
2451
+ emptyLabel,
2452
+ "aria-label": ariaLabel,
2453
+ id,
2454
+ name
2455
+ }, ref) {
2456
+ const [open, setOpen] = react.useState(false);
2457
+ const [value, setValue] = useControllableState({
2458
+ value: valueProp,
2459
+ defaultValue,
2460
+ onChange: onValueChange
2461
+ });
2462
+ return /* @__PURE__ */ jsxRuntime.jsxs(RadixPopover__namespace.Root, { open, onOpenChange: setOpen, children: [
2463
+ /* @__PURE__ */ jsxRuntime.jsx(RadixPopover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
2464
+ "button",
2465
+ {
2466
+ ref,
2467
+ id,
2468
+ type: "button",
2469
+ disabled,
2470
+ "aria-label": ariaLabel ?? placeholder,
2471
+ className: cn(
2472
+ "border-border bg-panel text-text flex cursor-pointer items-center gap-2 rounded-md border px-3 py-2 text-left text-[13px] outline-none",
2473
+ "transition-[border,box-shadow] duration-(--duration-micro)",
2474
+ "hover:bg-panel-2",
2475
+ "focus-visible:border-accent focus-visible:ring-accent-dim focus-visible:ring-[3px]",
2476
+ "disabled:cursor-not-allowed disabled:opacity-40"
2477
+ ),
2478
+ style: { width },
2479
+ children: [
2480
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-text-dim", children: "\u25A2" }),
2481
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-1 truncate", !value && "text-text-dim"), children: value ? format(value) : emptyLabel ?? placeholder })
2482
+ ]
2483
+ }
2484
+ ) }),
2485
+ /* @__PURE__ */ jsxRuntime.jsx(RadixPopover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2486
+ RadixPopover__namespace.Content,
2487
+ {
2488
+ align: "start",
2489
+ sideOffset: 6,
2490
+ className: "z-40 outline-none data-[state=open]:animate-[ship-pop-in_140ms_var(--easing-out)]",
2491
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2492
+ Calendar,
2493
+ {
2494
+ selected: value,
2495
+ defaultMonth: value?.getMonth(),
2496
+ defaultYear: value?.getFullYear(),
2497
+ onSelect: (date) => {
2498
+ setValue(date);
2499
+ setOpen(false);
2500
+ },
2501
+ isDateDisabled
2502
+ }
2503
+ )
2504
+ }
2505
+ ) }),
2506
+ name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: value ? value.toISOString() : "", readOnly: true })
2507
+ ] });
2508
+ });
2509
+ DatePicker.displayName = "DatePicker";
2510
+ var Dots = react.forwardRef(function Dots2({ total, current, onChange, className, "aria-label": ariaLabel = "Progress", ...props }, ref) {
2511
+ const interactive = typeof onChange === "function";
2512
+ return /* @__PURE__ */ jsxRuntime.jsx(
2513
+ "nav",
2514
+ {
2515
+ ref,
2516
+ "aria-label": ariaLabel,
2517
+ className: cn("inline-flex items-center gap-[6px]", className),
2518
+ ...props,
2519
+ children: Array.from({ length: total }).map((_, i) => {
2520
+ const isActive = i === current;
2521
+ const sharedClass = cn(
2522
+ "h-[6px] rounded-full transition-[width,background] duration-(--duration-micro)",
2523
+ isActive ? "w-[18px] bg-accent" : "w-[6px] bg-panel-2"
2524
+ );
2525
+ if (interactive) {
2526
+ return /* @__PURE__ */ jsxRuntime.jsx(
2527
+ "button",
2528
+ {
2529
+ type: "button",
2530
+ "aria-label": `Go to slide ${i + 1}`,
2531
+ "aria-current": isActive ? "true" : void 0,
2532
+ onClick: () => onChange?.(i),
2533
+ className: cn(
2534
+ sharedClass,
2535
+ "cursor-pointer outline-none",
2536
+ "focus-visible:ring-accent-dim focus-visible:ring-[3px]",
2537
+ !isActive && "hover:bg-border-strong"
2538
+ )
2539
+ },
2540
+ i
2541
+ );
2542
+ }
2543
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: sharedClass }, i);
2544
+ })
2545
+ }
2546
+ );
2547
+ });
2548
+ Dots.displayName = "Dots";
2549
+ var plateStyles = classVarianceAuthority.cva("grid h-12 w-12 place-items-center rounded-base text-[22px]", {
2550
+ variants: {
2551
+ tone: {
2552
+ accent: "bg-accent-dim text-accent",
2553
+ danger: "bg-[color-mix(in_oklab,var(--color-err),transparent_85%)] text-err",
2554
+ muted: "bg-panel-2 text-text-muted"
2555
+ }
2556
+ },
2557
+ defaultVariants: { tone: "accent" }
2558
+ });
2559
+ var EmptyState = react.forwardRef(function EmptyState2({ icon, title, description, action, chips, tone, className, ...props }, ref) {
2560
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2561
+ "div",
2562
+ {
2563
+ ref,
2564
+ className: cn(
2565
+ "rounded-base border-border bg-panel flex flex-col items-center gap-[10px] border border-dashed p-6 text-center",
2566
+ className
2567
+ ),
2568
+ ...props,
2569
+ children: [
2570
+ icon != null && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: plateStyles({ tone }), children: icon }),
2571
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[14px] font-medium", children: title }),
2572
+ description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-muted max-w-[260px] text-[12px] leading-[1.5]", children: description }),
2573
+ chips && chips.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full flex-col gap-1", children: chips.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx(
2574
+ "button",
2575
+ {
2576
+ type: "button",
2577
+ onClick: c.onClick,
2578
+ className: cn(
2579
+ "border-border bg-panel-2 text-text-muted cursor-pointer rounded-md border px-[10px] py-[6px] text-[11px]",
2580
+ "hover:border-border-strong hover:text-text outline-none",
2581
+ "focus-visible:ring-accent-dim focus-visible:ring-[3px]"
2582
+ ),
2583
+ children: c.label
2584
+ },
2585
+ i
2586
+ )) }),
2587
+ action
2588
+ ]
2589
+ }
2590
+ );
2591
+ });
2592
+ EmptyState.displayName = "EmptyState";
2593
+ function deriveExt(name) {
2594
+ const dot = name.lastIndexOf(".");
2595
+ if (dot < 0) return "FILE";
2596
+ return name.slice(dot + 1).slice(0, 4).toUpperCase();
2597
+ }
2598
+ var FileChip = react.forwardRef(function FileChip2({ name, size, progress, icon, onRemove, failed, className, ...props }, ref) {
2599
+ const ext = deriveExt(name);
2600
+ const showProgress = typeof progress === "number";
2601
+ const isComplete = showProgress && progress >= 100;
2602
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2603
+ "div",
2604
+ {
2605
+ ref,
2606
+ className: cn(
2607
+ "border-border bg-panel-2 flex max-w-[320px] items-center gap-[10px] rounded-md border px-3 py-2",
2608
+ className
2609
+ ),
2610
+ ...props,
2611
+ children: [
2612
+ /* @__PURE__ */ jsxRuntime.jsx(
2613
+ "span",
2614
+ {
2615
+ "aria-hidden": true,
2616
+ className: "border-border bg-panel text-text-dim grid h-6 w-6 shrink-0 place-items-center rounded-xs border font-mono text-[9px]",
2617
+ children: icon ?? ext
2618
+ }
2619
+ ),
2620
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
2621
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-[12px] font-medium", children: name }),
2622
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("font-mono text-[10px]", failed ? "text-err" : "text-text-dim"), children: [
2623
+ size,
2624
+ showProgress && !isComplete && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2625
+ " \xB7 ",
2626
+ Math.round(progress),
2627
+ "%"
2628
+ ] })
2629
+ ] }),
2630
+ showProgress && !isComplete && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-panel mt-1 h-[2px] overflow-hidden rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx(
2631
+ "div",
2632
+ {
2633
+ className: cn(
2634
+ "h-full transition-[width] duration-(--duration-step)",
2635
+ failed ? "bg-err" : "bg-accent"
2636
+ ),
2637
+ style: { width: `${Math.max(0, Math.min(100, progress))}%` }
2638
+ }
2639
+ ) })
2640
+ ] }),
2641
+ onRemove && /* @__PURE__ */ jsxRuntime.jsx(
2642
+ "button",
2643
+ {
2644
+ type: "button",
2645
+ "aria-label": `Remove ${name}`,
2646
+ onClick: onRemove,
2647
+ className: cn(
2648
+ "text-text-dim cursor-pointer border-0 bg-transparent p-0 text-[14px] leading-none",
2649
+ "hover:text-text focus-visible:ring-accent-dim rounded-xs outline-none focus-visible:ring-[3px]"
2650
+ ),
2651
+ children: "\xD7"
2652
+ }
2653
+ )
2654
+ ]
2655
+ }
2656
+ );
2657
+ });
2658
+ FileChip.displayName = "FileChip";
2659
+ var Menubar = react.forwardRef(function Menubar2({ className, ...props }, ref) {
2660
+ return /* @__PURE__ */ jsxRuntime.jsx(
2661
+ RadixMenubar__namespace.Root,
2662
+ {
2663
+ ref,
2664
+ className: cn(
2665
+ "border-border bg-panel flex h-[30px] items-center gap-[2px] border-b px-3",
2666
+ className
2667
+ ),
2668
+ ...props
2669
+ }
2670
+ );
2671
+ });
2672
+ Menubar.displayName = "Menubar";
2673
+ var MenubarMenu = RadixMenubar__namespace.Menu;
2674
+ var MenubarTrigger = react.forwardRef(
2675
+ function MenubarTrigger2({ className, ...props }, ref) {
2676
+ return /* @__PURE__ */ jsxRuntime.jsx(
2677
+ RadixMenubar__namespace.Trigger,
2678
+ {
2679
+ ref,
2680
+ className: cn(
2681
+ "text-text cursor-pointer rounded-xs border-0 bg-transparent px-[10px] py-1 text-[12px] outline-none",
2682
+ "transition-colors duration-(--duration-micro)",
2683
+ "data-[state=open]:bg-panel-2 hover:bg-panel-2",
2684
+ "focus-visible:ring-accent-dim focus-visible:ring-[3px]",
2685
+ className
2686
+ ),
2687
+ ...props
2688
+ }
2689
+ );
2690
+ }
2691
+ );
2692
+ MenubarTrigger.displayName = "MenubarTrigger";
2693
+ var MenubarContent = react.forwardRef(
2694
+ function MenubarContent2({ className, sideOffset = 6, align = "start", ...props }, ref) {
2695
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixMenubar__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2696
+ RadixMenubar__namespace.Content,
2697
+ {
2698
+ ref,
2699
+ sideOffset,
2700
+ align,
2701
+ className: cn(
2702
+ "border-border-strong bg-panel z-40 min-w-[180px] rounded-md border p-1 shadow-lg outline-none",
2703
+ "data-[state=open]:animate-[ship-pop-in_140ms_var(--easing-out)]",
2704
+ className
2705
+ ),
2706
+ ...props
2707
+ }
2708
+ ) });
2709
+ }
2710
+ );
2711
+ MenubarContent.displayName = "MenubarContent";
2712
+ var itemBase3 = cn(
2713
+ "flex items-center gap-2 rounded-sm px-[10px] py-[6px] text-[12px] cursor-pointer outline-none",
2714
+ "data-[highlighted]:bg-panel-2",
2715
+ "data-[disabled]:opacity-40 data-[disabled]:cursor-not-allowed"
2716
+ );
2717
+ var MenubarItem = react.forwardRef(function MenubarItem2({ trailing, destructive, className, children, ...props }, ref) {
2718
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2719
+ RadixMenubar__namespace.Item,
2720
+ {
2721
+ ref,
2722
+ className: cn(itemBase3, destructive ? "text-err" : "text-text", className),
2723
+ ...props,
2724
+ children: [
2725
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children }),
2726
+ trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-dim font-mono text-[10px]", children: trailing })
2727
+ ]
2728
+ }
2729
+ );
2730
+ });
2731
+ MenubarItem.displayName = "MenubarItem";
2732
+ var MenubarSeparator = react.forwardRef(
2733
+ function MenubarSeparator2({ className, ...props }, ref) {
2734
+ return /* @__PURE__ */ jsxRuntime.jsx(
2735
+ RadixMenubar__namespace.Separator,
2736
+ {
2737
+ ref,
2738
+ className: cn("bg-border my-1 h-px", className),
2739
+ ...props
2740
+ }
2741
+ );
2742
+ }
2743
+ );
2744
+ MenubarSeparator.displayName = "MenubarSeparator";
2745
+ function buildRange(page, total, siblings) {
2746
+ if (total <= 0) return [];
2747
+ const items = [];
2748
+ const left = Math.max(2, page - siblings);
2749
+ const right = Math.min(total - 1, page + siblings);
2750
+ items.push(1);
2751
+ if (left > 2) items.push("start-ellipsis");
2752
+ for (let i = left; i <= right; i++) items.push(i);
2753
+ if (right < total - 1) items.push("end-ellipsis");
2754
+ if (total > 1) items.push(total);
2755
+ return items;
2756
+ }
2757
+ var Pagination = react.forwardRef(function Pagination2({ page, total, onPageChange, siblings = 1, className, ...props }, ref) {
2758
+ const items = buildRange(page, total, siblings);
2759
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2760
+ "nav",
2761
+ {
2762
+ ref,
2763
+ "aria-label": "Pagination",
2764
+ className: cn("inline-flex items-center gap-1", className),
2765
+ ...props,
2766
+ children: [
2767
+ /* @__PURE__ */ jsxRuntime.jsx(
2768
+ IconButton,
2769
+ {
2770
+ size: "sm",
2771
+ variant: "ghost",
2772
+ icon: "\u2039",
2773
+ "aria-label": "Previous page",
2774
+ disabled: page <= 1,
2775
+ onClick: () => onPageChange(Math.max(1, page - 1))
2776
+ }
2777
+ ),
2778
+ items.map((item, i) => {
2779
+ if (item === "start-ellipsis" || item === "end-ellipsis") {
2780
+ return /* @__PURE__ */ jsxRuntime.jsx(
2781
+ "span",
2782
+ {
2783
+ "aria-hidden": true,
2784
+ className: "text-text-dim grid h-[26px] min-w-[26px] place-items-center px-2 font-mono text-[12px]",
2785
+ children: "\u2026"
2786
+ },
2787
+ `ellipsis-${i}`
2788
+ );
2789
+ }
2790
+ const isActive = item === page;
2791
+ return /* @__PURE__ */ jsxRuntime.jsx(
2792
+ "button",
2793
+ {
2794
+ type: "button",
2795
+ "aria-label": `Go to page ${item}`,
2796
+ "aria-current": isActive ? "page" : void 0,
2797
+ onClick: () => onPageChange(item),
2798
+ className: cn(
2799
+ "h-[26px] min-w-[26px] rounded-[5px] px-2 font-mono text-[12px] outline-none",
2800
+ "cursor-pointer transition-colors duration-(--duration-micro)",
2801
+ "focus-visible:ring-accent-dim focus-visible:ring-[3px]",
2802
+ isActive ? "bg-accent-dim text-accent border-accent border" : "text-text-muted hover:bg-panel-2 hover:text-text border border-transparent"
2803
+ ),
2804
+ children: item
2805
+ },
2806
+ item
2807
+ );
2808
+ }),
2809
+ /* @__PURE__ */ jsxRuntime.jsx(
2810
+ IconButton,
2811
+ {
2812
+ size: "sm",
2813
+ variant: "ghost",
2814
+ icon: "\u203A",
2815
+ "aria-label": "Next page",
2816
+ disabled: page >= total,
2817
+ onClick: () => onPageChange(Math.min(total, page + 1))
2818
+ }
2819
+ )
2820
+ ]
2821
+ }
2822
+ );
2823
+ });
2824
+ Pagination.displayName = "Pagination";
2825
+ var trackStyles = classVarianceAuthority.cva("w-full rounded-full bg-panel-2 overflow-hidden", {
2826
+ variants: {
2827
+ size: {
2828
+ sm: "h-[3px]",
2829
+ md: "h-[4px]",
2830
+ lg: "h-[6px]"
2831
+ }
2832
+ },
2833
+ defaultVariants: { size: "md" }
2834
+ });
2835
+ var fillStyles = classVarianceAuthority.cva("h-full rounded-full transition-[width] duration-(--duration-step)", {
2836
+ variants: {
2837
+ tone: {
2838
+ accent: "bg-accent",
2839
+ ok: "bg-ok",
2840
+ warn: "bg-warn",
2841
+ err: "bg-err"
2842
+ }
2843
+ },
2844
+ defaultVariants: { tone: "accent" }
2845
+ });
2846
+ var Progress = react.forwardRef(function Progress2({
2847
+ value = 0,
2848
+ max = 100,
2849
+ indeterminate = false,
2850
+ label,
2851
+ showValue = true,
2852
+ tone,
2853
+ size,
2854
+ className,
2855
+ ...props
2856
+ }, ref) {
2857
+ const clamped = Math.min(max, Math.max(0, value));
2858
+ const pct = max > 0 ? clamped / max * 100 : 0;
2859
+ const display = Math.round(pct);
2860
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex w-full flex-col gap-2", className), ...props, children: [
2861
+ label != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex text-[12px]", children: [
2862
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-muted", children: label }),
2863
+ showValue && !indeterminate && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-text ml-auto font-mono tabular-nums", children: [
2864
+ display,
2865
+ "%"
2866
+ ] })
2867
+ ] }),
2868
+ /* @__PURE__ */ jsxRuntime.jsx(
2869
+ "div",
2870
+ {
2871
+ role: "progressbar",
2872
+ "aria-valuemin": 0,
2873
+ "aria-valuemax": max,
2874
+ "aria-valuenow": indeterminate ? void 0 : display,
2875
+ "aria-label": typeof label === "string" ? label : void 0,
2876
+ className: trackStyles({ size }),
2877
+ children: indeterminate ? /* @__PURE__ */ jsxRuntime.jsx(
2878
+ "span",
2879
+ {
2880
+ "aria-hidden": true,
2881
+ className: cn(
2882
+ "block h-full w-[40%] rounded-full",
2883
+ fillStyles({ tone }),
2884
+ "animate-[ship-indeterminate_1.4s_linear_infinite]"
2885
+ )
2886
+ }
2887
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: fillStyles({ tone }), style: { width: `${pct}%` } })
2888
+ }
2889
+ )
2890
+ ] });
2891
+ });
2892
+ Progress.displayName = "Progress";
2893
+ var toneStrokeClass = {
2894
+ accent: "stroke-accent",
2895
+ ok: "stroke-ok",
2896
+ warn: "stroke-warn",
2897
+ err: "stroke-err"
2898
+ };
2899
+ var RadialProgress = react.forwardRef(
2900
+ function RadialProgress2({
2901
+ value,
2902
+ max = 100,
2903
+ size = 64,
2904
+ thickness = 4,
2905
+ tone,
2906
+ children,
2907
+ className,
2908
+ "aria-label": ariaLabel,
2909
+ ...props
2910
+ }, ref) {
2911
+ const clamped = Math.min(max, Math.max(0, value));
2912
+ const pct = max > 0 ? clamped / max * 100 : 0;
2913
+ const r = (size - thickness) / 2;
2914
+ const c = 2 * Math.PI * r;
2915
+ const dash = pct / 100 * c;
2916
+ const resolvedTone = tone ?? (clamped >= max ? "ok" : "accent");
2917
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2918
+ "div",
2919
+ {
2920
+ ref,
2921
+ role: "progressbar",
2922
+ "aria-valuemin": 0,
2923
+ "aria-valuemax": max,
2924
+ "aria-valuenow": Math.round(pct),
2925
+ "aria-label": ariaLabel ?? `${Math.round(pct)}%`,
2926
+ className: cn("relative inline-grid place-items-center", className),
2927
+ style: { width: size, height: size },
2928
+ ...props,
2929
+ children: [
2930
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [
2931
+ /* @__PURE__ */ jsxRuntime.jsx(
2932
+ "circle",
2933
+ {
2934
+ cx: size / 2,
2935
+ cy: size / 2,
2936
+ r,
2937
+ fill: "none",
2938
+ strokeWidth: thickness,
2939
+ className: "stroke-panel-2"
2940
+ }
2941
+ ),
2942
+ /* @__PURE__ */ jsxRuntime.jsx(
2943
+ "circle",
2944
+ {
2945
+ cx: size / 2,
2946
+ cy: size / 2,
2947
+ r,
2948
+ fill: "none",
2949
+ strokeWidth: thickness,
2950
+ strokeLinecap: "round",
2951
+ strokeDasharray: `${dash} ${c}`,
2952
+ transform: `rotate(-90 ${size / 2} ${size / 2})`,
2953
+ className: cn(
2954
+ "transition-[stroke-dasharray] duration-(--duration-step)",
2955
+ toneStrokeClass[resolvedTone]
2956
+ )
2957
+ }
2958
+ )
2959
+ ] }),
2960
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 grid place-items-center font-mono text-[11px] font-medium tabular-nums", children: children ?? `${Math.round(pct)}%` })
2961
+ ]
2962
+ }
2963
+ );
2964
+ }
2965
+ );
2966
+ RadialProgress.displayName = "RadialProgress";
2967
+ var Sidebar = react.forwardRef(function Sidebar2({ width = 240, className, style, ...props }, ref) {
2968
+ return /* @__PURE__ */ jsxRuntime.jsx(
2969
+ "aside",
2970
+ {
2971
+ ref,
2972
+ style: { width, ...style },
2973
+ className: cn(
2974
+ "border-border bg-panel flex h-full flex-col gap-2 border-r p-[14px]",
2975
+ className
2976
+ ),
2977
+ ...props
2978
+ }
2979
+ );
2980
+ });
2981
+ Sidebar.displayName = "Sidebar";
2982
+ var NavItem = react.forwardRef(function NavItem2({ icon, label, active, badge, href, disabled, className, onClick, ...props }, ref) {
2983
+ const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2984
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "w-[14px] text-center opacity-80", children: icon }),
2985
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label }),
2986
+ badge != null && /* @__PURE__ */ jsxRuntime.jsx(
2987
+ "span",
2988
+ {
2989
+ className: cn(
2990
+ "rounded-xs px-[6px] py-px font-mono text-[10px]",
2991
+ active ? "bg-accent text-on-accent" : "bg-panel-2 text-text-muted"
2992
+ ),
2993
+ children: badge
2994
+ }
2995
+ )
2996
+ ] });
2997
+ const baseClass = cn(
2998
+ "flex cursor-pointer items-center gap-[10px] rounded-xs px-2 py-[6px] text-[13px] outline-none",
2999
+ "transition-colors duration-(--duration-micro)",
3000
+ "focus-visible:ring-[3px] focus-visible:ring-accent-dim",
3001
+ active ? "bg-accent-dim text-accent" : "text-text hover:bg-panel-2",
3002
+ disabled && "opacity-50 pointer-events-none",
3003
+ className
3004
+ );
3005
+ if (href) {
3006
+ return /* @__PURE__ */ jsxRuntime.jsx(
3007
+ "a",
3008
+ {
3009
+ ref,
3010
+ href,
3011
+ "aria-current": active ? "page" : void 0,
3012
+ "aria-disabled": disabled || void 0,
3013
+ className: baseClass,
3014
+ onClick,
3015
+ ...props,
3016
+ children: inner
3017
+ }
3018
+ );
3019
+ }
3020
+ return /* @__PURE__ */ jsxRuntime.jsx(
3021
+ "a",
3022
+ {
3023
+ ref,
3024
+ role: "button",
3025
+ tabIndex: disabled ? -1 : 0,
3026
+ "aria-current": active ? "page" : void 0,
3027
+ "aria-disabled": disabled || void 0,
3028
+ className: baseClass,
3029
+ onClick,
3030
+ onKeyDown: (e) => {
3031
+ if (e.key === "Enter" || e.key === " ") {
3032
+ e.preventDefault();
3033
+ e.currentTarget.click();
3034
+ }
3035
+ },
3036
+ ...props,
3037
+ children: inner
3038
+ }
3039
+ );
3040
+ });
3041
+ NavItem.displayName = "NavItem";
3042
+ var NavSection = react.forwardRef(function NavSection2({ label, action, className, children, ...props }, ref) {
3043
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex flex-col gap-1", className), ...props, children: [
3044
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-text-dim flex items-center px-2 pt-2 font-mono text-[9px] tracking-[1.4px] uppercase", children: [
3045
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: label }),
3046
+ action
3047
+ ] }),
3048
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[2px]", children })
3049
+ ] });
3050
+ });
3051
+ NavSection.displayName = "NavSection";
3052
+ function buildPath(values, w, h) {
3053
+ if (values.length === 0) return { line: "", area: "" };
3054
+ const pad = 2;
3055
+ const min = Math.min(...values);
3056
+ const max = Math.max(...values);
3057
+ const range = max - min || 1;
3058
+ const stepX = values.length === 1 ? 0 : (w - pad * 2) / (values.length - 1);
3059
+ const points = values.map((v, i) => {
3060
+ const x = pad + i * stepX;
3061
+ const y = pad + (1 - (v - min) / range) * (h - pad * 2);
3062
+ return `${x.toFixed(2)},${y.toFixed(2)}`;
3063
+ });
3064
+ const line = `M${points.join(" L")}`;
3065
+ const area = `${line} L${(pad + (values.length - 1) * stepX).toFixed(2)},${(h - pad).toFixed(
3066
+ 2
3067
+ )} L${pad.toFixed(2)},${(h - pad).toFixed(2)} Z`;
3068
+ return { line, area };
3069
+ }
3070
+ var Sparkline = react.forwardRef(function Sparkline2({
3071
+ values,
3072
+ width = 160,
3073
+ height = 32,
3074
+ stroke = "currentColor",
3075
+ strokeWidth = 1.5,
3076
+ fill = false,
3077
+ className,
3078
+ "aria-label": ariaLabel = "Trend",
3079
+ ...props
3080
+ }, ref) {
3081
+ const { line, area } = react.useMemo(() => buildPath(values, width, height), [values, width, height]);
3082
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3083
+ "svg",
3084
+ {
3085
+ ref,
3086
+ width,
3087
+ height,
3088
+ viewBox: `0 0 ${width} ${height}`,
3089
+ role: "img",
3090
+ "aria-label": ariaLabel,
3091
+ className: cn("inline-block", className),
3092
+ ...props,
3093
+ children: [
3094
+ fill && /* @__PURE__ */ jsxRuntime.jsx("path", { d: area, fill: stroke, fillOpacity: 0.16, stroke: "none" }),
3095
+ /* @__PURE__ */ jsxRuntime.jsx(
3096
+ "path",
3097
+ {
3098
+ d: line,
3099
+ fill: "none",
3100
+ stroke,
3101
+ strokeWidth,
3102
+ strokeLinecap: "round",
3103
+ strokeLinejoin: "round"
3104
+ }
3105
+ )
3106
+ ]
3107
+ }
3108
+ );
3109
+ });
3110
+ Sparkline.displayName = "Sparkline";
3111
+ var sizes = {
3112
+ sm: { box: "h-3 w-3", border: "border-[2px]" },
3113
+ md: { box: "h-4 w-4", border: "border-[2px]" },
3114
+ lg: { box: "h-5 w-5", border: "border-[2px]" }
3115
+ };
3116
+ var Spinner2 = react.forwardRef(function Spinner3({ size = "md", label = "Loading", className, ...props }, ref) {
3117
+ const s = sizes[size];
3118
+ return /* @__PURE__ */ jsxRuntime.jsx(
3119
+ "span",
3120
+ {
3121
+ ref,
3122
+ role: "status",
3123
+ "aria-label": label,
3124
+ className: cn("inline-block", className),
3125
+ ...props,
3126
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3127
+ "span",
3128
+ {
3129
+ "aria-hidden": true,
3130
+ className: cn(
3131
+ "border-panel-2 border-t-accent block animate-[ship-spin_0.7s_linear_infinite] rounded-full",
3132
+ s.box,
3133
+ s.border
3134
+ )
3135
+ }
3136
+ )
3137
+ }
3138
+ );
3139
+ });
3140
+ Spinner2.displayName = "Spinner";
3141
+ var dotBase = "h-6 w-6 rounded-full grid place-items-center text-[11px] font-mono font-semibold border";
3142
+ var dotStateClass = {
3143
+ done: "bg-accent text-on-accent border-accent",
3144
+ current: "bg-accent-dim text-accent border-accent",
3145
+ upcoming: "bg-panel text-text-dim border-border"
3146
+ };
3147
+ var labelStateClass = {
3148
+ done: "text-text",
3149
+ current: "text-text font-medium",
3150
+ upcoming: "text-text-dim"
3151
+ };
3152
+ function stateFor(index, current) {
3153
+ if (index < current) return "done";
3154
+ if (index === current) return "current";
3155
+ return "upcoming";
3156
+ }
3157
+ var Stepper = react.forwardRef(function Stepper2({ steps, current, className, ...props }, ref) {
3158
+ return /* @__PURE__ */ jsxRuntime.jsx(
3159
+ "div",
3160
+ {
3161
+ ref,
3162
+ role: "list",
3163
+ "aria-label": "Progress",
3164
+ className: cn("flex w-full items-center", className),
3165
+ ...props,
3166
+ children: steps.map((label, i) => {
3167
+ const state = stateFor(i, current);
3168
+ const connectorActive = i < current;
3169
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
3170
+ /* @__PURE__ */ jsxRuntime.jsxs(
3171
+ "div",
3172
+ {
3173
+ role: "listitem",
3174
+ "aria-current": state === "current" ? "step" : void 0,
3175
+ className: "flex items-center gap-2",
3176
+ children: [
3177
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn(dotBase, dotStateClass[state]), children: state === "done" ? "\u2713" : i + 1 }),
3178
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[12px]", labelStateClass[state]), children: label })
3179
+ ]
3180
+ }
3181
+ ),
3182
+ i < steps.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
3183
+ "span",
3184
+ {
3185
+ "aria-hidden": true,
3186
+ className: cn("mx-3 h-px flex-1", connectorActive ? "bg-accent" : "bg-border")
3187
+ }
3188
+ )
3189
+ ] }, label);
3190
+ })
3191
+ }
3192
+ );
3193
+ });
3194
+ Stepper.displayName = "Stepper";
3195
+ var TabsVariantContext = react.createContext("underline");
3196
+ var tabsListStyles = classVarianceAuthority.cva("", {
3197
+ variants: {
3198
+ variant: {
3199
+ underline: "flex gap-6 border-b border-border",
3200
+ pill: "inline-flex gap-1 rounded-base border border-border bg-panel-2 p-[3px]"
3201
+ }
3202
+ }
3203
+ });
3204
+ var tabsTriggerStyles = classVarianceAuthority.cva(
3205
+ "cursor-pointer outline-none transition-colors duration-(--duration-micro) focus-visible:ring-[3px] focus-visible:ring-accent-dim",
3206
+ {
3207
+ variants: {
3208
+ variant: {
3209
+ underline: cn(
3210
+ "relative -mb-px inline-flex items-center px-[2px] py-2 text-[13px]",
3211
+ "border-b-2 border-transparent text-text-muted",
3212
+ "hover:text-text",
3213
+ "data-[state=active]:border-accent data-[state=active]:text-text data-[state=active]:font-medium"
3214
+ ),
3215
+ pill: cn(
3216
+ "inline-flex items-center rounded-sm px-[14px] py-[6px] text-[12px] font-normal",
3217
+ "text-text-muted hover:text-text",
3218
+ "data-[state=active]:bg-panel data-[state=active]:text-text data-[state=active]:font-medium",
3219
+ "data-[state=active]:shadow-sm"
3220
+ )
3221
+ }
3222
+ }
3223
+ }
3224
+ );
3225
+ var Tabs = react.forwardRef(function Tabs2({ variant = "underline", className, ...props }, ref) {
3226
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsxRuntime.jsx(
3227
+ RadixTabs__namespace.Root,
3228
+ {
3229
+ ref,
3230
+ className: cn("flex flex-col", variant === "underline" && "gap-3", className),
3231
+ ...props
3232
+ }
3233
+ ) });
3234
+ });
3235
+ Tabs.displayName = "Tabs";
3236
+ var TabsList = react.forwardRef(function TabsList2({ className, ...props }, ref) {
3237
+ const variant = react.useContext(TabsVariantContext);
3238
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixTabs__namespace.List, { ref, className: cn(tabsListStyles({ variant }), className), ...props });
3239
+ });
3240
+ TabsList.displayName = "TabsList";
3241
+ var Tab = react.forwardRef(function Tab2({ className, ...props }, ref) {
3242
+ const variant = react.useContext(TabsVariantContext);
3243
+ return /* @__PURE__ */ jsxRuntime.jsx(
3244
+ RadixTabs__namespace.Trigger,
3245
+ {
3246
+ ref,
3247
+ className: cn(tabsTriggerStyles({ variant }), className),
3248
+ ...props
3249
+ }
3250
+ );
3251
+ });
3252
+ Tab.displayName = "Tab";
3253
+ var TabsContent = react.forwardRef(
3254
+ function TabsContent2({ className, ...props }, ref) {
3255
+ return /* @__PURE__ */ jsxRuntime.jsx(
3256
+ RadixTabs__namespace.Content,
3257
+ {
3258
+ ref,
3259
+ className: cn(
3260
+ "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]",
3261
+ className
3262
+ ),
3263
+ ...props
3264
+ }
3265
+ );
3266
+ }
3267
+ );
3268
+ TabsContent.displayName = "TabsContent";
3269
+ var ringClass = {
3270
+ accent: "border-accent",
3271
+ ok: "border-ok",
3272
+ warn: "border-warn",
3273
+ err: "border-err",
3274
+ muted: "border-text-dim"
3275
+ };
3276
+ var Timeline = react.forwardRef(function Timeline2({ events, className, children, ...props }, ref) {
3277
+ return /* @__PURE__ */ jsxRuntime.jsx(
3278
+ "ol",
3279
+ {
3280
+ ref,
3281
+ className: cn(
3282
+ "relative pl-6",
3283
+ "before:bg-border before:absolute before:top-[6px] before:bottom-[6px] before:left-[7px] before:w-px",
3284
+ className
3285
+ ),
3286
+ ...props,
3287
+ children: events ? events.map((e, i) => /* @__PURE__ */ jsxRuntime.jsx(TimelineItem, { tone: e.tone, time: e.time, description: e.description, children: e.title }, i)) : children
3288
+ }
3289
+ );
3290
+ });
3291
+ Timeline.displayName = "Timeline";
3292
+ var TimelineItem = react.forwardRef(function TimelineItem2({ tone = "accent", description, time, className, children, ...props }, ref) {
3293
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { ref, className: cn("relative mb-[18px] last:mb-0", className), ...props, children: [
3294
+ /* @__PURE__ */ jsxRuntime.jsx(
3295
+ "span",
3296
+ {
3297
+ "aria-hidden": true,
3298
+ className: cn(
3299
+ "bg-bg absolute top-[4px] -left-6 h-[14px] w-[14px] rounded-full border-2",
3300
+ ringClass[tone]
3301
+ )
3302
+ }
3303
+ ),
3304
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[13px] font-medium", children }),
3305
+ description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-muted text-[12px]", children: description }),
3306
+ time && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-text-dim mt-[2px] font-mono text-[10px]", children: time })
3307
+ ] });
3308
+ });
3309
+ TimelineItem.displayName = "TimelineItem";
3310
+ var Topbar = react.forwardRef(function Topbar2({ title, leading, actions, className, children, ...props }, ref) {
3311
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3312
+ "header",
3313
+ {
3314
+ ref,
3315
+ className: cn(
3316
+ "border-border bg-panel flex h-[52px] items-center gap-4 border-b px-5",
3317
+ className
3318
+ ),
3319
+ ...props,
3320
+ children: [
3321
+ leading,
3322
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[13px] font-medium", children: title }),
3323
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center" }),
3324
+ actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: actions }),
3325
+ children
3326
+ ]
3327
+ }
3328
+ );
3329
+ });
3330
+ Topbar.displayName = "Topbar";
3331
+ var Tree = react.forwardRef(function Tree2({
3332
+ items,
3333
+ expanded: expandedProp,
3334
+ defaultExpanded,
3335
+ onExpandedChange,
3336
+ selected: selectedProp,
3337
+ defaultSelected,
3338
+ onSelect,
3339
+ className,
3340
+ ...props
3341
+ }, ref) {
3342
+ const [expanded, setExpanded] = useControllableState({
3343
+ value: expandedProp instanceof Set ? expandedProp : expandedProp,
3344
+ defaultValue: defaultExpanded ? new Set(defaultExpanded) : /* @__PURE__ */ new Set(),
3345
+ onChange: onExpandedChange
3346
+ });
3347
+ const [selected, setSelected] = useControllableState({
3348
+ value: selectedProp,
3349
+ defaultValue: defaultSelected,
3350
+ onChange: onSelect
3351
+ });
3352
+ const toggle = react.useCallback(
3353
+ (id) => {
3354
+ setExpanded((prev) => {
3355
+ const next = new Set(prev ?? []);
3356
+ if (next.has(id)) next.delete(id);
3357
+ else next.add(id);
3358
+ return next;
3359
+ });
3360
+ },
3361
+ [setExpanded]
3362
+ );
3363
+ return /* @__PURE__ */ jsxRuntime.jsx(
3364
+ "ul",
3365
+ {
3366
+ ref,
3367
+ role: "tree",
3368
+ className: cn("flex flex-col gap-px text-[12px]", className),
3369
+ ...props,
3370
+ children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
3371
+ TreeItemRow,
3372
+ {
3373
+ item,
3374
+ level: 1,
3375
+ expanded: expanded ?? /* @__PURE__ */ new Set(),
3376
+ selected,
3377
+ onToggle: toggle,
3378
+ onSelect: (id) => setSelected(id)
3379
+ },
3380
+ item.id
3381
+ ))
3382
+ }
3383
+ );
3384
+ });
3385
+ Tree.displayName = "Tree";
3386
+ function TreeItemRow({ item, level, expanded, selected, onToggle, onSelect }) {
3387
+ const hasChildren = !!item.children && item.children.length > 0;
3388
+ const isExpanded = hasChildren && expanded.has(item.id);
3389
+ const isSelected = selected === item.id;
3390
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { role: "none", children: [
3391
+ /* @__PURE__ */ jsxRuntime.jsxs(
3392
+ "div",
3393
+ {
3394
+ role: "treeitem",
3395
+ "aria-level": level,
3396
+ "aria-expanded": hasChildren ? isExpanded : void 0,
3397
+ "aria-selected": isSelected,
3398
+ tabIndex: isSelected ? 0 : -1,
3399
+ onClick: () => {
3400
+ onSelect(item.id);
3401
+ if (hasChildren) onToggle(item.id);
3402
+ },
3403
+ onKeyDown: (e) => {
3404
+ if (e.key === "Enter" || e.key === " ") {
3405
+ e.preventDefault();
3406
+ onSelect(item.id);
3407
+ if (hasChildren) onToggle(item.id);
3408
+ } else if (e.key === "ArrowRight" && hasChildren && !isExpanded) {
3409
+ e.preventDefault();
3410
+ onToggle(item.id);
3411
+ } else if (e.key === "ArrowLeft" && hasChildren && isExpanded) {
3412
+ e.preventDefault();
3413
+ onToggle(item.id);
3414
+ }
3415
+ },
3416
+ style: { paddingLeft: 4 + (level - 1) * 16 },
3417
+ className: cn(
3418
+ "flex cursor-pointer items-center gap-[6px] rounded-xs py-[5px] pr-2 outline-none",
3419
+ "focus-visible:ring-accent-dim focus-visible:ring-[3px]",
3420
+ isSelected ? "bg-accent-dim text-accent" : "text-text hover:bg-panel-2"
3421
+ ),
3422
+ children: [
3423
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-text-dim grid w-3 place-items-center text-[10px]", children: hasChildren ? isExpanded ? "\u25BE" : "\u25B8" : "" }),
3424
+ item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-[12px] opacity-80", children: item.icon }),
3425
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: item.label }),
3426
+ item.trailing
3427
+ ]
3428
+ }
3429
+ ),
3430
+ hasChildren && isExpanded && /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "group", className: "flex flex-col gap-px", children: item.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
3431
+ TreeItemRow,
3432
+ {
3433
+ item: child,
3434
+ level: level + 1,
3435
+ expanded,
3436
+ selected,
3437
+ onToggle,
3438
+ onSelect
3439
+ },
3440
+ child.id
3441
+ )) })
3442
+ ] });
3443
+ }
3444
+
3445
+ exports.Alert = Alert;
3446
+ exports.AlertDialog = AlertDialog;
3447
+ exports.AlertDialogAction = AlertDialogAction;
3448
+ exports.AlertDialogCancel = AlertDialogCancel;
3449
+ exports.AlertDialogRoot = AlertDialogRoot;
3450
+ exports.AlertDialogTrigger = AlertDialogTrigger;
3451
+ exports.Avatar = Avatar;
3452
+ exports.AvatarGroup = AvatarGroup;
3453
+ exports.Badge = Badge;
3454
+ exports.Banner = Banner;
3455
+ exports.Breadcrumbs = Breadcrumbs;
3456
+ exports.Button = Button;
3457
+ exports.ButtonGroup = ButtonGroup;
3458
+ exports.Calendar = Calendar;
3459
+ exports.Card = Card;
3460
+ exports.Checkbox = Checkbox;
3461
+ exports.Chip = Chip;
3462
+ exports.Combobox = Combobox;
3463
+ exports.CommandPalette = CommandPalette;
3464
+ exports.ContextMenu = ContextMenu;
3465
+ exports.ContextMenuContent = ContextMenuContent;
3466
+ exports.ContextMenuItem = ContextMenuItem;
3467
+ exports.ContextMenuPortal = ContextMenuPortal;
3468
+ exports.ContextMenuRoot = ContextMenuRoot;
3469
+ exports.ContextMenuSeparator = ContextMenuSeparator;
3470
+ exports.ContextMenuTrigger = ContextMenuTrigger;
3471
+ exports.Crumb = Crumb;
3472
+ exports.DataTable = DataTable;
3473
+ exports.DatePicker = DatePicker;
3474
+ exports.Dialog = Dialog;
3475
+ exports.DialogClose = DialogClose;
3476
+ exports.DialogContent = DialogContent;
3477
+ exports.DialogOverlay = DialogOverlay;
3478
+ exports.DialogPortal = DialogPortal;
3479
+ exports.DialogRoot = DialogRoot;
3480
+ exports.DialogTrigger = DialogTrigger;
3481
+ exports.Dots = Dots;
3482
+ exports.Drawer = Drawer;
3483
+ exports.DropdownMenu = DropdownMenu;
3484
+ exports.DropdownMenuContent = DropdownMenuContent;
3485
+ exports.DropdownMenuGroup = DropdownMenuGroup;
3486
+ exports.DropdownMenuLabel = DropdownMenuLabel;
3487
+ exports.DropdownMenuPortal = DropdownMenuPortal;
3488
+ exports.DropdownMenuRadioGroup = DropdownMenuRadioGroup;
3489
+ exports.DropdownMenuRoot = DropdownMenuRoot;
3490
+ exports.DropdownMenuTrigger = DropdownMenuTrigger;
3491
+ exports.EmptyState = EmptyState;
3492
+ exports.FAB = FAB;
3493
+ exports.Field = Field;
3494
+ exports.FileChip = FileChip;
3495
+ exports.HoverCard = HoverCard;
3496
+ exports.HoverCardContent = HoverCardContent;
3497
+ exports.HoverCardPortal = HoverCardPortal;
3498
+ exports.HoverCardRoot = HoverCardRoot;
3499
+ exports.HoverCardTrigger = HoverCardTrigger;
3500
+ exports.IconButton = IconButton;
3501
+ exports.Input = Input;
3502
+ exports.Kbd = Kbd;
3503
+ exports.MenuCheckboxItem = MenuCheckboxItem;
3504
+ exports.MenuItem = MenuItem;
3505
+ exports.MenuSeparator = MenuSeparator;
3506
+ exports.Menubar = Menubar;
3507
+ exports.MenubarContent = MenubarContent;
3508
+ exports.MenubarItem = MenubarItem;
3509
+ exports.MenubarMenu = MenubarMenu;
3510
+ exports.MenubarSeparator = MenubarSeparator;
3511
+ exports.MenubarTrigger = MenubarTrigger;
3512
+ exports.NavItem = NavItem;
3513
+ exports.NavSection = NavSection;
3514
+ exports.OTP = OTP;
3515
+ exports.Pagination = Pagination;
3516
+ exports.Popover = Popover;
3517
+ exports.PopoverAnchor = PopoverAnchor;
3518
+ exports.PopoverArrow = PopoverArrow;
3519
+ exports.PopoverClose = PopoverClose;
3520
+ exports.PopoverContent = PopoverContent;
3521
+ exports.PopoverPortal = PopoverPortal;
3522
+ exports.PopoverRoot = PopoverRoot;
3523
+ exports.PopoverTrigger = PopoverTrigger;
3524
+ exports.Progress = Progress;
3525
+ exports.RadialProgress = RadialProgress;
3526
+ exports.Radio = Radio;
3527
+ exports.RadioGroup = RadioGroup;
3528
+ exports.SearchInput = SearchInput;
3529
+ exports.Select = Select;
3530
+ exports.SelectContent = SelectContent;
3531
+ exports.SelectGroup = SelectGroup;
3532
+ exports.SelectItem = SelectItem;
3533
+ exports.SelectLabel = SelectLabel;
3534
+ exports.SelectRoot = SelectRoot;
3535
+ exports.SelectTrigger = SelectTrigger;
3536
+ exports.SelectValue = SelectValue;
3537
+ exports.Sheet = Sheet;
3538
+ exports.Sidebar = Sidebar;
3539
+ exports.Skeleton = Skeleton;
3540
+ exports.Slider = Slider;
3541
+ exports.Sparkline = Sparkline;
3542
+ exports.Spinner = Spinner2;
3543
+ exports.SplitButton = SplitButton;
3544
+ exports.StatCard = StatCard;
3545
+ exports.StatusDot = StatusDot;
3546
+ exports.Stepper = Stepper;
3547
+ exports.Switch = Switch;
3548
+ exports.Tab = Tab;
3549
+ exports.Tabs = Tabs;
3550
+ exports.TabsContent = TabsContent;
3551
+ exports.TabsList = TabsList;
3552
+ exports.Tag = Tag;
3553
+ exports.Textarea = Textarea;
3554
+ exports.Timeline = Timeline;
3555
+ exports.TimelineItem = TimelineItem;
3556
+ exports.ToastCard = ToastCard;
3557
+ exports.ToastProvider = ToastProvider;
3558
+ exports.Tooltip = Tooltip;
3559
+ exports.TooltipArrow = TooltipArrow;
3560
+ exports.TooltipContent = TooltipContent;
3561
+ exports.TooltipPortal = TooltipPortal;
3562
+ exports.TooltipProvider = TooltipProvider;
3563
+ exports.TooltipRoot = TooltipRoot;
3564
+ exports.TooltipTrigger = TooltipTrigger;
3565
+ exports.Topbar = Topbar;
3566
+ exports.Tree = Tree;
3567
+ exports.badgeStyles = badgeStyles;
3568
+ exports.buttonStyles = buttonStyles;
3569
+ exports.cardStyles = cardStyles;
3570
+ exports.cn = cn;
3571
+ exports.filterCommandItems = filterCommandItems;
3572
+ exports.iconButtonStyles = iconButtonStyles;
3573
+ exports.useControllableState = useControllableState;
3574
+ exports.useDisclosure = useDisclosure;
3575
+ exports.useEscape = useEscape;
3576
+ exports.useKeyboardList = useKeyboardList;
3577
+ exports.useOutsideClick = useOutsideClick;
3578
+ exports.useTheme = useTheme;
3579
+ exports.useToast = useToast;
3580
+ //# sourceMappingURL=index.cjs.map
3581
+ //# sourceMappingURL=index.cjs.map