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