@codraoss/ui 0.9.4

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.
Files changed (44) hide show
  1. package/LICENSE +625 -0
  2. package/README.md +15 -0
  3. package/dist/chunk-HCQJTSV3.js +39 -0
  4. package/dist/chunk-HCQJTSV3.js.map +1 -0
  5. package/dist/chunk-OU66JJZD.js +7 -0
  6. package/dist/chunk-OU66JJZD.js.map +1 -0
  7. package/dist/chunk-PZ5AY32C.js +10 -0
  8. package/dist/chunk-PZ5AY32C.js.map +1 -0
  9. package/dist/chunk-TXNSYK4G.js +23 -0
  10. package/dist/chunk-TXNSYK4G.js.map +1 -0
  11. package/dist/components/motion/index.d.ts +92 -0
  12. package/dist/components/motion/index.js +643 -0
  13. package/dist/components/motion/index.js.map +1 -0
  14. package/dist/hooks/index.d.ts +3 -0
  15. package/dist/hooks/index.js +8 -0
  16. package/dist/hooks/index.js.map +1 -0
  17. package/dist/index.d.ts +241 -0
  18. package/dist/index.js +1144 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/lib/ease.d.ts +3 -0
  21. package/dist/lib/ease.js +8 -0
  22. package/dist/lib/ease.js.map +1 -0
  23. package/dist/lib/file-tree.d.ts +16 -0
  24. package/dist/lib/file-tree.js +46 -0
  25. package/dist/lib/file-tree.js.map +1 -0
  26. package/dist/lib/highlight.d.ts +14 -0
  27. package/dist/lib/highlight.js +35 -0
  28. package/dist/lib/highlight.js.map +1 -0
  29. package/dist/lib/markdown-plugins.d.ts +6 -0
  30. package/dist/lib/markdown-plugins.js +11041 -0
  31. package/dist/lib/markdown-plugins.js.map +1 -0
  32. package/dist/lib/prompt-diff.d.ts +21 -0
  33. package/dist/lib/prompt-diff.js +95 -0
  34. package/dist/lib/prompt-diff.js.map +1 -0
  35. package/dist/lib/selection.d.ts +11 -0
  36. package/dist/lib/selection.js +15 -0
  37. package/dist/lib/selection.js.map +1 -0
  38. package/dist/lib/theme.d.ts +14 -0
  39. package/dist/lib/theme.js +78 -0
  40. package/dist/lib/theme.js.map +1 -0
  41. package/dist/lib/utils.d.ts +15 -0
  42. package/dist/lib/utils.js +14 -0
  43. package/dist/lib/utils.js.map +1 -0
  44. package/package.json +150 -0
package/dist/index.js ADDED
@@ -0,0 +1,1144 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCQJTSV3.js";
4
+ import {
5
+ EASE_OUT
6
+ } from "./chunk-OU66JJZD.js";
7
+ import "./chunk-PZ5AY32C.js";
8
+
9
+ // src/components/alert.tsx
10
+ import * as React from "react";
11
+ import { AlertCircle, CheckCircle2, AlertTriangle, Info } from "lucide-react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var variants = {
14
+ default: {
15
+ bg: "var(--info-bg)",
16
+ border: "var(--info-border)",
17
+ color: "var(--info)",
18
+ icon: Info
19
+ },
20
+ destructive: {
21
+ bg: "var(--danger-bg)",
22
+ border: "var(--danger-border)",
23
+ color: "var(--danger)",
24
+ icon: AlertCircle
25
+ },
26
+ warning: {
27
+ bg: "var(--warning-bg)",
28
+ border: "var(--warning-border)",
29
+ color: "var(--warning)",
30
+ icon: AlertTriangle
31
+ },
32
+ success: {
33
+ bg: "var(--success-bg)",
34
+ border: "var(--success-border)",
35
+ color: "var(--success)",
36
+ icon: CheckCircle2
37
+ }
38
+ };
39
+ var Alert = React.forwardRef(
40
+ ({ className, variant = "default", icon: IconOverride, children, ...props }, ref) => {
41
+ const config = variants[variant];
42
+ const Icon = IconOverride || config.icon;
43
+ return /* @__PURE__ */ jsxs(
44
+ "div",
45
+ {
46
+ ref,
47
+ role: "alert",
48
+ className: cn(
49
+ "flex gap-3 rounded-lg border px-4 py-3 text-sm",
50
+ className
51
+ ),
52
+ style: {
53
+ backgroundColor: config.bg,
54
+ borderColor: config.border,
55
+ color: config.color
56
+ },
57
+ ...props,
58
+ children: [
59
+ /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 mt-0.5" }),
60
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children })
61
+ ]
62
+ }
63
+ );
64
+ }
65
+ );
66
+ Alert.displayName = "Alert";
67
+
68
+ // src/components/badge.tsx
69
+ import "react";
70
+ import "class-variance-authority";
71
+
72
+ // src/components/badge-variants.ts
73
+ import { cva } from "class-variance-authority";
74
+ var badgeVariants = cva(
75
+ "inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-[11px] font-medium transition-colors",
76
+ {
77
+ variants: {
78
+ variant: {
79
+ default: "bg-primary/15 text-primary",
80
+ secondary: "bg-ui-fill/45 text-ui-default",
81
+ neutral: "bg-ui-fill/45 text-ui-default",
82
+ info: "bg-info/15 text-info",
83
+ success: "bg-success/15 text-success",
84
+ warning: "bg-warning/15 text-warning",
85
+ danger: "bg-danger/15 text-danger",
86
+ outline: "text-ui-default ring-1 ring-inset ring-ui-line bg-transparent"
87
+ }
88
+ },
89
+ defaultVariants: { variant: "default" }
90
+ }
91
+ );
92
+
93
+ // src/components/badge.tsx
94
+ import { jsx as jsx2 } from "react/jsx-runtime";
95
+ function Badge({ className, variant, ...props }) {
96
+ return /* @__PURE__ */ jsx2("div", { className: cn(badgeVariants({ variant }), className), ...props });
97
+ }
98
+
99
+ // src/components/button.tsx
100
+ import * as React3 from "react";
101
+ import { useRender } from "@base-ui/react/use-render";
102
+ import "class-variance-authority";
103
+ import { Loader2 } from "lucide-react";
104
+
105
+ // src/components/button-variants.ts
106
+ import { cva as cva2 } from "class-variance-authority";
107
+ var buttonVariants = cva2(
108
+ "relative inline-flex select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
109
+ {
110
+ variants: {
111
+ variant: {
112
+ primary: "border border-[var(--btn-primary-border)] bg-[var(--btn-primary-surface)] text-[var(--btn-primary-fg)] hover:bg-[var(--btn-primary-hover)]",
113
+ secondary: "border border-ui-line bg-ui-base text-ui-default hover:bg-ui-fill/60",
114
+ default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 active:scale-[.98]",
115
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
116
+ "destructive-outline": "border border-danger-border bg-danger-bg/40 text-danger shadow-sm hover:bg-destructive hover:text-destructive-foreground hover:border-destructive",
117
+ "warning-outline": "border border-warning-border bg-warning-bg/40 text-warning shadow-sm hover:bg-warning-bg hover:border-warning",
118
+ outline: "border border-zinc-200 bg-white shadow-sm hover:bg-zinc-50 hover:text-zinc-900 dark:border-white/10 dark:bg-white/[0.06] dark:hover:bg-white/[0.1] dark:hover:text-foreground",
119
+ ghost: "hover:bg-secondary hover:text-secondary-foreground",
120
+ link: "text-primary underline-offset-4 hover:underline",
121
+ accent: "bg-accent text-accent-foreground shadow-sm hover:bg-accent/90 active:scale-[.98]"
122
+ },
123
+ size: {
124
+ default: "h-9 rounded-md px-4 py-2 text-sm",
125
+ sm: "h-8 rounded-md px-3 text-xs",
126
+ base: "h-9 rounded-md px-3 text-sm",
127
+ lg: "h-11 rounded-md px-6 text-sm",
128
+ xs: "h-6 rounded-md px-1.5 text-xs",
129
+ icon: "h-9 w-9 rounded-md"
130
+ }
131
+ },
132
+ defaultVariants: { variant: "default", size: "default" }
133
+ }
134
+ );
135
+
136
+ // src/components/button.tsx
137
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
138
+ var SQUARE_WIDTH = {
139
+ xs: "w-6 p-0",
140
+ sm: "w-8 p-0",
141
+ base: "w-9 p-0",
142
+ default: "w-9 p-0",
143
+ lg: "w-11 p-0",
144
+ icon: "p-0"
145
+ };
146
+ function shapeClass(shape, size) {
147
+ if (shape === "base") return "";
148
+ return cn(SQUARE_WIDTH[size ?? "default"], shape === "circle" && "rounded-full");
149
+ }
150
+ var Button = React3.forwardRef(
151
+ ({ className, variant, size, shape = "base", asChild = false, icon, loading, children, ...props }, ref) => {
152
+ const classes = cn(buttonVariants({ variant, size }), shapeClass(shape, size), className);
153
+ return useRender({
154
+ render: asChild && React3.isValidElement(children) ? children : void 0,
155
+ defaultTagName: "button",
156
+ ref,
157
+ props: {
158
+ className: classes,
159
+ ...props,
160
+ ...asChild ? {} : {
161
+ disabled: props.disabled || loading,
162
+ children: /* @__PURE__ */ jsxs2(Fragment, { children: [
163
+ loading ? /* @__PURE__ */ jsx3(Loader2, { className: "size-4 animate-spin" }) : icon,
164
+ children
165
+ ] })
166
+ }
167
+ }
168
+ });
169
+ }
170
+ );
171
+ Button.displayName = "Button";
172
+ var LinkButton = React3.forwardRef(
173
+ ({ className, variant, size, shape = "base", icon, external, children, ...props }, ref) => /* @__PURE__ */ jsxs2(
174
+ "a",
175
+ {
176
+ ref,
177
+ className: cn(buttonVariants({ variant, size }), shapeClass(shape, size), className),
178
+ ...external ? { target: "_blank", rel: "noopener noreferrer" } : {},
179
+ ...props,
180
+ children: [
181
+ icon,
182
+ children
183
+ ]
184
+ }
185
+ )
186
+ );
187
+ LinkButton.displayName = "LinkButton";
188
+
189
+ // src/components/confirm-dialog.tsx
190
+ import { Dialog } from "@base-ui/react/dialog";
191
+ import { AlertTriangle as AlertTriangle2 } from "lucide-react";
192
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
193
+ function ConfirmDialog({
194
+ open,
195
+ onOpenChange,
196
+ title,
197
+ description,
198
+ confirmLabel = "Continue",
199
+ cancelLabel = "Cancel",
200
+ confirmVariant = "default",
201
+ onConfirm
202
+ }) {
203
+ return /* @__PURE__ */ jsx4(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs3(Dialog.Portal, { children: [
204
+ /* @__PURE__ */ jsx4(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-background/75 backdrop-blur-sm transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0" }),
205
+ /* @__PURE__ */ jsxs3(Dialog.Popup, { className: "fixed left-1/2 top-1/2 z-50 w-[calc(100vw-1.5rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-ui-line bg-card p-5 shadow-2xl transition-[opacity,transform] duration-150 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0", children: [
206
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-3", children: [
207
+ /* @__PURE__ */ jsx4("span", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[var(--warning-bg)] text-[var(--warning)]", children: /* @__PURE__ */ jsx4(AlertTriangle2, { size: 18 }) }),
208
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
209
+ /* @__PURE__ */ jsx4(Dialog.Title, { className: "text-sm font-semibold text-foreground", children: title }),
210
+ /* @__PURE__ */ jsx4(Dialog.Description, { className: "mt-1 text-sm text-muted-foreground", children: description })
211
+ ] })
212
+ ] }),
213
+ /* @__PURE__ */ jsxs3("div", { className: "mt-5 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", children: [
214
+ /* @__PURE__ */ jsx4(Dialog.Close, { render: /* @__PURE__ */ jsx4(Button, { variant: "outline" }), children: cancelLabel }),
215
+ /* @__PURE__ */ jsx4(
216
+ Button,
217
+ {
218
+ variant: confirmVariant,
219
+ onClick: () => {
220
+ onConfirm();
221
+ onOpenChange(false);
222
+ },
223
+ children: confirmLabel
224
+ }
225
+ )
226
+ ] })
227
+ ] })
228
+ ] }) });
229
+ }
230
+
231
+ // src/components/input.tsx
232
+ import * as React4 from "react";
233
+ import { jsx as jsx5 } from "react/jsx-runtime";
234
+ var SIZE_CLASS = {
235
+ xs: "h-6 rounded-md px-1.5 text-xs",
236
+ sm: "h-8 rounded-md px-2 text-xs",
237
+ base: "h-9 rounded-md px-3 text-sm",
238
+ lg: "h-10 rounded-md px-4 text-base"
239
+ };
240
+ var Input = React4.forwardRef(
241
+ ({ className, size = "base", ...props }, ref) => /* @__PURE__ */ jsx5(
242
+ "input",
243
+ {
244
+ ref,
245
+ className: cn(
246
+ "w-full border border-ui-line bg-ui-base text-ui-default transition-colors placeholder:text-ui-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-brand/40 disabled:cursor-not-allowed disabled:opacity-50",
247
+ SIZE_CLASS[size],
248
+ className
249
+ ),
250
+ ...props
251
+ }
252
+ )
253
+ );
254
+ Input.displayName = "Input";
255
+
256
+ // src/components/layer-card.tsx
257
+ import * as React5 from "react";
258
+ import { jsx as jsx6 } from "react/jsx-runtime";
259
+ var LayerCard = React5.forwardRef(
260
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
261
+ "div",
262
+ {
263
+ ref,
264
+ className: cn("rounded-lg border border-ui-line bg-ui-base", className),
265
+ ...props
266
+ }
267
+ )
268
+ );
269
+ LayerCard.displayName = "LayerCard";
270
+
271
+ // src/components/select.tsx
272
+ import { domAnimation, LazyMotion, useReducedMotion } from "motion/react";
273
+ import {
274
+ useEffect,
275
+ useId,
276
+ useLayoutEffect,
277
+ useRef,
278
+ useState
279
+ } from "react";
280
+ import { createPortal } from "react-dom";
281
+
282
+ // src/components/select-panel.tsx
283
+ import { Check } from "lucide-react";
284
+ import { m } from "motion/react";
285
+
286
+ // src/components/select-shared.ts
287
+ var CHEVRON_TRANSITION = { type: "spring", duration: 0.4, bounce: 0.3 };
288
+ var LIST_VARIANTS = {
289
+ hidden: {},
290
+ show: { transition: { staggerChildren: 0.02, delayChildren: 0.03 } }
291
+ };
292
+ var ITEM_VARIANTS = {
293
+ hidden: { opacity: 0, y: -5, filter: "blur(2px)" },
294
+ show: { opacity: 1, y: 0, filter: "blur(0px)" }
295
+ };
296
+ var INSTANT_TRANSITION = { duration: 0 };
297
+
298
+ // src/components/select-panel.tsx
299
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
300
+ var REDUCED_TRANSITION = { duration: 0.12 };
301
+ var GAP_TRANSITION_OPEN = { type: "spring", duration: 0.44, bounce: 0.45, delay: 0.09 };
302
+ var GAP_TRANSITION_CLOSED = { type: "spring", duration: 0.26, bounce: 0.1 };
303
+ var RADIUS_TRANSITION_OPEN = { duration: 0.26, ease: EASE_OUT, delay: 0.1 };
304
+ var RADIUS_TRANSITION_CLOSED = { duration: 0.15, ease: EASE_OUT };
305
+ var OPACITY_TRANSITION_OPEN = { duration: 0.18 };
306
+ var OPACITY_TRANSITION_CLOSED = { duration: 0.16, delay: 0.1 };
307
+ var HEIGHT_TRANSITION_OPEN = { type: "spring", duration: 0.4, bounce: 0.14 };
308
+ var HEIGHT_TRANSITION_CLOSED = { duration: 0.24, ease: EASE_OUT, delay: 0.1 };
309
+ function SelectPanel({
310
+ panelRef,
311
+ innerRef,
312
+ optionRefs,
313
+ listId,
314
+ triggerId,
315
+ options,
316
+ value,
317
+ highlightedIndex,
318
+ open,
319
+ isTop,
320
+ reduce,
321
+ height,
322
+ rect,
323
+ onSelect,
324
+ onHighlight
325
+ }) {
326
+ const nearGap = open ? 8 : 0;
327
+ const nearRadius = open ? 7 : 0;
328
+ const gapT = open ? GAP_TRANSITION_OPEN : GAP_TRANSITION_CLOSED;
329
+ const radiusT = open ? RADIUS_TRANSITION_OPEN : RADIUS_TRANSITION_CLOSED;
330
+ return /* @__PURE__ */ jsx7(
331
+ m.div,
332
+ {
333
+ ref: panelRef,
334
+ id: listId,
335
+ role: "listbox",
336
+ "aria-labelledby": triggerId,
337
+ "aria-hidden": !open,
338
+ initial: false,
339
+ animate: reduce ? { opacity: open ? 1 : 0, height: open ? height : 0 } : {
340
+ opacity: open ? 1 : 0,
341
+ height: open ? height : 0,
342
+ // gap opens on the side facing the trigger
343
+ marginTop: isTop ? 0 : nearGap,
344
+ marginBottom: isTop ? nearGap : 0,
345
+ // near corners go flat->round; far corners stay rounded
346
+ borderTopLeftRadius: isTop ? 7 : nearRadius,
347
+ borderTopRightRadius: isTop ? 7 : nearRadius,
348
+ borderBottomLeftRadius: isTop ? nearRadius : 7,
349
+ borderBottomRightRadius: isTop ? nearRadius : 7
350
+ },
351
+ transition: reduce ? REDUCED_TRANSITION : {
352
+ opacity: open ? OPACITY_TRANSITION_OPEN : OPACITY_TRANSITION_CLOSED,
353
+ height: open ? HEIGHT_TRANSITION_OPEN : HEIGHT_TRANSITION_CLOSED,
354
+ marginTop: isTop ? INSTANT_TRANSITION : gapT,
355
+ marginBottom: isTop ? gapT : INSTANT_TRANSITION,
356
+ borderTopLeftRadius: isTop ? INSTANT_TRANSITION : radiusT,
357
+ borderTopRightRadius: isTop ? INSTANT_TRANSITION : radiusT,
358
+ borderBottomLeftRadius: isTop ? radiusT : INSTANT_TRANSITION,
359
+ borderBottomRightRadius: isTop ? radiusT : INSTANT_TRANSITION
360
+ },
361
+ style: {
362
+ position: "fixed",
363
+ left: rect?.left ?? 0,
364
+ width: rect?.width ?? 0,
365
+ top: isTop ? void 0 : rect?.bottom ?? 0,
366
+ bottom: isTop ? window.innerHeight - (rect?.top ?? 0) : void 0,
367
+ transformOrigin: isTop ? "bottom" : "top",
368
+ overflow: "hidden",
369
+ pointerEvents: open ? "auto" : "none"
370
+ },
371
+ className: "z-50 border border-ui-line bg-ui-base shadow-lg shadow-black/[0.04] dark:shadow-black/40",
372
+ children: /* @__PURE__ */ jsx7(
373
+ m.ul,
374
+ {
375
+ ref: innerRef,
376
+ variants: reduce ? void 0 : LIST_VARIANTS,
377
+ initial: false,
378
+ animate: open ? "show" : "hidden",
379
+ className: "max-h-[min(28rem,60vh)] overflow-y-auto p-1",
380
+ children: options.map((option, index) => {
381
+ const selected = option.value === value;
382
+ const highlighted = index === highlightedIndex;
383
+ return /* @__PURE__ */ jsx7(m.li, { variants: reduce ? void 0 : ITEM_VARIANTS, children: /* @__PURE__ */ jsxs4(
384
+ "button",
385
+ {
386
+ ref: (node) => {
387
+ optionRefs.current[index] = node;
388
+ },
389
+ id: `${listId}-option-${index}`,
390
+ type: "button",
391
+ role: "option",
392
+ "aria-selected": selected,
393
+ tabIndex: -1,
394
+ onMouseEnter: () => onHighlight(index),
395
+ onClick: () => onSelect(option.value),
396
+ className: cn(
397
+ // `whitespace-nowrap`: on the 72px "rows per page" select, the check icon ate the width and "10" wrapped to stacked digits.
398
+ "flex w-full items-center justify-between gap-2 whitespace-nowrap rounded-md px-2.5 py-1.5 text-left text-sm outline-none transition-colors",
399
+ selected ? "bg-ui-brand/10 font-medium text-ui-brand" : "text-ui-default hover:bg-ui-fill hover:text-ui-strong focus-visible:bg-ui-fill",
400
+ highlighted && !selected && "bg-ui-fill text-ui-strong"
401
+ ),
402
+ children: [
403
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: option.label }),
404
+ selected ? /* @__PURE__ */ jsx7(Check, { className: "h-3.5 w-3.5 shrink-0" }) : null
405
+ ]
406
+ }
407
+ ) }, option.value);
408
+ })
409
+ }
410
+ )
411
+ }
412
+ );
413
+ }
414
+
415
+ // src/components/select-trigger.tsx
416
+ import { ChevronDown } from "lucide-react";
417
+ import { m as m2 } from "motion/react";
418
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
419
+ var RADIUS_OPEN = [0, 0, 7];
420
+ var RADIUS_CLOSED = [7, 0, 7];
421
+ var RADIUS_TRANSITION_OPEN2 = { duration: 0.46, times: [0, 0.4, 1], ease: EASE_OUT };
422
+ var RADIUS_TRANSITION_CLOSED2 = { duration: 0.34, times: [0, 0.5, 1], ease: EASE_OUT };
423
+ function SelectTrigger({
424
+ triggerRef,
425
+ triggerId,
426
+ listId,
427
+ labelId,
428
+ activeDescendantId,
429
+ open,
430
+ isTop,
431
+ reduce,
432
+ selectedOption,
433
+ placeholder,
434
+ leadingIcon,
435
+ variant,
436
+ className,
437
+ style,
438
+ onToggle,
439
+ onKeyDown
440
+ }) {
441
+ const kf = open ? RADIUS_OPEN : RADIUS_CLOSED;
442
+ const kfT = reduce ? INSTANT_TRANSITION : open ? RADIUS_TRANSITION_OPEN2 : RADIUS_TRANSITION_CLOSED2;
443
+ return /* @__PURE__ */ jsxs5(
444
+ m2.button,
445
+ {
446
+ ref: triggerRef,
447
+ type: "button",
448
+ id: triggerId,
449
+ "aria-haspopup": "listbox",
450
+ "aria-expanded": open,
451
+ "aria-controls": listId,
452
+ "aria-labelledby": labelId ? `${labelId} ${triggerId}` : void 0,
453
+ "aria-activedescendant": activeDescendantId,
454
+ onClick: onToggle,
455
+ onKeyDown,
456
+ initial: false,
457
+ animate: {
458
+ borderTopLeftRadius: isTop ? kf : 7,
459
+ borderTopRightRadius: isTop ? kf : 7,
460
+ borderBottomLeftRadius: isTop ? 7 : kf,
461
+ borderBottomRightRadius: isTop ? 7 : kf
462
+ },
463
+ transition: {
464
+ borderTopLeftRadius: isTop ? kfT : INSTANT_TRANSITION,
465
+ borderTopRightRadius: isTop ? kfT : INSTANT_TRANSITION,
466
+ borderBottomLeftRadius: isTop ? INSTANT_TRANSITION : kfT,
467
+ borderBottomRightRadius: isTop ? INSTANT_TRANSITION : kfT
468
+ },
469
+ style,
470
+ className: cn(
471
+ "relative z-10 flex h-9 w-full items-center justify-between gap-2 border border-ui-line px-3 py-2 text-sm font-normal text-ui-default outline-none transition-colors",
472
+ variant === "page" ? "bg-ui-base" : "bg-ui-fill/50",
473
+ "hover:bg-ui-fill/70 focus-visible:ring-2 focus-visible:ring-ui-brand/40 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
474
+ !selectedOption && "text-ui-subtle",
475
+ className
476
+ ),
477
+ children: [
478
+ /* @__PURE__ */ jsxs5("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
479
+ leadingIcon && /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-primary/70", children: leadingIcon }),
480
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 truncate", children: selectedOption ? selectedOption.label : placeholder })
481
+ ] }),
482
+ /* @__PURE__ */ jsx8(
483
+ m2.span,
484
+ {
485
+ "aria-hidden": true,
486
+ animate: { rotate: open ? 180 : 0 },
487
+ transition: reduce ? INSTANT_TRANSITION : CHEVRON_TRANSITION,
488
+ className: "shrink-0 text-ui-subtle",
489
+ children: /* @__PURE__ */ jsx8(ChevronDown, { className: "h-4 w-4" })
490
+ }
491
+ )
492
+ ]
493
+ }
494
+ );
495
+ }
496
+
497
+ // src/components/select.tsx
498
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
499
+ function Select({
500
+ value,
501
+ onValueChange,
502
+ options,
503
+ placeholder = "Select...",
504
+ label,
505
+ className,
506
+ triggerClassName,
507
+ triggerStyle,
508
+ leadingIcon,
509
+ variant = "page"
510
+ }) {
511
+ const reduce = useReducedMotion() ?? false;
512
+ const baseId = useId();
513
+ const triggerId = `${baseId}-trigger`;
514
+ const listId = `${baseId}-list`;
515
+ const labelId = `${baseId}-label`;
516
+ const triggerRef = useRef(null);
517
+ const labelRef = useRef(null);
518
+ const panelRef = useRef(null);
519
+ const innerRef = useRef(null);
520
+ const [open, setOpen] = useState(false);
521
+ const [placement, setPlacement] = useState("bottom");
522
+ const [height, setHeight] = useState(0);
523
+ const [rect, setRect] = useState(null);
524
+ const [highlightedIndex, setHighlightedIndex] = useState(0);
525
+ const optionRefs = useRef([]);
526
+ const highlightSource = useRef("keyboard");
527
+ const selectedOption = options.find((opt) => opt.value === value);
528
+ useEffect(() => {
529
+ if (!open) return;
530
+ highlightSource.current = "keyboard";
531
+ const idx = options.findIndex((opt) => opt.value === value);
532
+ setHighlightedIndex(idx >= 0 ? idx : 0);
533
+ }, [open]);
534
+ useEffect(() => {
535
+ if (!open || highlightSource.current !== "keyboard") return;
536
+ optionRefs.current[highlightedIndex]?.scrollIntoView({ block: "nearest" });
537
+ }, [open, highlightedIndex]);
538
+ useEffect(() => {
539
+ if (!open) return;
540
+ const onKey = (e) => e.key === "Escape" && setOpen(false);
541
+ const onPointer = (e) => {
542
+ const target = e.target;
543
+ if (triggerRef.current?.contains(target)) return;
544
+ if (panelRef.current?.contains(target)) return;
545
+ if (labelRef.current?.contains(target)) return;
546
+ setOpen(false);
547
+ };
548
+ window.addEventListener("keydown", onKey);
549
+ window.addEventListener("pointerdown", onPointer);
550
+ return () => {
551
+ window.removeEventListener("keydown", onKey);
552
+ window.removeEventListener("pointerdown", onPointer);
553
+ };
554
+ }, [open]);
555
+ useLayoutEffect(() => {
556
+ const node = innerRef.current;
557
+ if (!node) return;
558
+ const measure = () => setHeight(node.offsetHeight);
559
+ measure();
560
+ const observer = new ResizeObserver(measure);
561
+ observer.observe(node);
562
+ return () => observer.disconnect();
563
+ }, []);
564
+ useLayoutEffect(() => {
565
+ if (!open) return;
566
+ const trigger = triggerRef.current;
567
+ if (!trigger) return;
568
+ let frame = null;
569
+ const update = () => {
570
+ frame = null;
571
+ const r = trigger.getBoundingClientRect();
572
+ setRect({ left: r.left, width: r.width, top: r.top, bottom: r.bottom });
573
+ const h = innerRef.current?.offsetHeight ?? 0;
574
+ const below = window.innerHeight - r.bottom;
575
+ const above = r.top;
576
+ setPlacement(below < h + 16 && above > below ? "top" : "bottom");
577
+ };
578
+ const scheduleUpdate = (e) => {
579
+ if (e && e.target instanceof Node && panelRef.current?.contains(e.target)) return;
580
+ if (frame !== null) return;
581
+ frame = requestAnimationFrame(update);
582
+ };
583
+ update();
584
+ window.addEventListener("scroll", scheduleUpdate, true);
585
+ window.addEventListener("resize", scheduleUpdate);
586
+ return () => {
587
+ if (frame !== null) cancelAnimationFrame(frame);
588
+ window.removeEventListener("scroll", scheduleUpdate, true);
589
+ window.removeEventListener("resize", scheduleUpdate);
590
+ };
591
+ }, [open]);
592
+ const moveHighlight = (next) => {
593
+ highlightSource.current = "keyboard";
594
+ setHighlightedIndex(Math.min(Math.max(next, 0), options.length - 1));
595
+ };
596
+ const onTriggerKeyDown = (e) => {
597
+ if (!open) {
598
+ if (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Enter" || e.key === " ") {
599
+ e.preventDefault();
600
+ setOpen(true);
601
+ }
602
+ return;
603
+ }
604
+ if (options.length === 0) return;
605
+ switch (e.key) {
606
+ case "ArrowDown":
607
+ e.preventDefault();
608
+ moveHighlight(highlightedIndex + 1);
609
+ break;
610
+ case "ArrowUp":
611
+ e.preventDefault();
612
+ moveHighlight(highlightedIndex - 1);
613
+ break;
614
+ case "Home":
615
+ e.preventDefault();
616
+ moveHighlight(0);
617
+ break;
618
+ case "End":
619
+ e.preventDefault();
620
+ moveHighlight(options.length - 1);
621
+ break;
622
+ case "Enter":
623
+ case " ":
624
+ e.preventDefault();
625
+ onValueChange(options[highlightedIndex].value);
626
+ setOpen(false);
627
+ break;
628
+ case "Tab":
629
+ setOpen(false);
630
+ break;
631
+ default:
632
+ break;
633
+ }
634
+ };
635
+ const selectOption = (next) => {
636
+ onValueChange(next);
637
+ setOpen(false);
638
+ };
639
+ const highlightOption = (index) => {
640
+ highlightSource.current = "pointer";
641
+ setHighlightedIndex(index);
642
+ };
643
+ const isTop = placement === "top";
644
+ return /* @__PURE__ */ jsx9(LazyMotion, { features: domAnimation, children: /* @__PURE__ */ jsxs6("div", { className: cn("flex flex-col gap-1.5", className), children: [
645
+ label && /* @__PURE__ */ jsx9(
646
+ "label",
647
+ {
648
+ ref: labelRef,
649
+ id: labelId,
650
+ htmlFor: triggerId,
651
+ className: "text-[10px] font-bold uppercase tracking-wider text-ui-subtle",
652
+ children: label
653
+ }
654
+ ),
655
+ /* @__PURE__ */ jsx9("div", { className: "relative", children: /* @__PURE__ */ jsx9(
656
+ SelectTrigger,
657
+ {
658
+ triggerRef,
659
+ triggerId,
660
+ listId,
661
+ labelId: label ? labelId : void 0,
662
+ activeDescendantId: open && options[highlightedIndex] ? `${listId}-option-${highlightedIndex}` : void 0,
663
+ open,
664
+ isTop,
665
+ reduce,
666
+ selectedOption,
667
+ placeholder,
668
+ leadingIcon,
669
+ variant,
670
+ className: triggerClassName,
671
+ style: triggerStyle,
672
+ onToggle: () => setOpen((v) => !v),
673
+ onKeyDown: onTriggerKeyDown
674
+ }
675
+ ) }),
676
+ createPortal(
677
+ /* @__PURE__ */ jsx9(
678
+ SelectPanel,
679
+ {
680
+ panelRef,
681
+ innerRef,
682
+ optionRefs,
683
+ listId,
684
+ triggerId,
685
+ options,
686
+ value,
687
+ highlightedIndex,
688
+ open,
689
+ isTop,
690
+ reduce,
691
+ height,
692
+ rect,
693
+ onSelect: selectOption,
694
+ onHighlight: highlightOption
695
+ }
696
+ ),
697
+ document.body
698
+ )
699
+ ] }) });
700
+ }
701
+
702
+ // src/components/switch.tsx
703
+ import * as React6 from "react";
704
+ import { Switch as BaseSwitch } from "@base-ui/react/switch";
705
+ import { jsx as jsx10 } from "react/jsx-runtime";
706
+ var Switch = React6.forwardRef(
707
+ ({ className, onCheckedChange, ...props }, ref) => /* @__PURE__ */ jsx10(
708
+ BaseSwitch.Root,
709
+ {
710
+ ref,
711
+ onCheckedChange: (checked) => onCheckedChange?.(checked),
712
+ className: cn(
713
+ // Squarish track + knob (Cloudflare-dashboard switch shape).
714
+ "relative inline-flex h-4 w-7 shrink-0 cursor-pointer items-center rounded-[5px] p-[2px] transition-colors duration-200",
715
+ // Dark mode: lighter zinc when off (reads against the page), deeper lime when on (knob doesn't blend).
716
+ "bg-ui-fill dark:bg-[oklch(40%_0_0)]",
717
+ "data-checked:bg-ui-brand dark:data-checked:bg-[oklch(64%_0.21_118)]",
718
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-brand/40 focus-visible:ring-offset-1 focus-visible:ring-offset-ui-base",
719
+ "data-disabled:cursor-not-allowed data-disabled:opacity-50",
720
+ className
721
+ ),
722
+ ...props,
723
+ children: /* @__PURE__ */ jsx10(BaseSwitch.Thumb, { className: "h-3 w-3 rounded-[3px] bg-white shadow-sm transition-transform duration-200 data-checked:translate-x-3" })
724
+ }
725
+ )
726
+ );
727
+ Switch.displayName = "Switch";
728
+
729
+ // src/components/text.tsx
730
+ import "react";
731
+ import { cva as cva3 } from "class-variance-authority";
732
+ import { jsx as jsx11 } from "react/jsx-runtime";
733
+ var textVariants = cva3("", {
734
+ variants: {
735
+ variant: {
736
+ body: "text-ui-default",
737
+ secondary: "text-ui-subtle",
738
+ strong: "text-ui-strong"
739
+ },
740
+ size: {
741
+ sm: "text-sm",
742
+ base: "text-base"
743
+ },
744
+ bold: {
745
+ true: "font-semibold",
746
+ false: ""
747
+ }
748
+ },
749
+ defaultVariants: { variant: "body", size: "base", bold: false }
750
+ });
751
+ function Text({ as: Comp = "p", variant, size, bold, className, ...props }) {
752
+ return /* @__PURE__ */ jsx11(Comp, { className: cn(textVariants({ variant, size, bold }), className), ...props });
753
+ }
754
+
755
+ // src/components/skeleton.tsx
756
+ import "react";
757
+ import { jsx as jsx12 } from "react/jsx-runtime";
758
+ var Skeleton = ({
759
+ width,
760
+ height,
761
+ borderRadius,
762
+ className = "",
763
+ style
764
+ }) => {
765
+ return /* @__PURE__ */ jsx12(
766
+ "div",
767
+ {
768
+ className: cn("skeleton", className),
769
+ style: {
770
+ width: width ?? "100%",
771
+ height: height ?? "1rem",
772
+ borderRadius: borderRadius ?? void 0,
773
+ ...style
774
+ }
775
+ }
776
+ );
777
+ };
778
+
779
+ // src/components/empty-state.tsx
780
+ import "react";
781
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
782
+ function EmptyState({ icon, title, description, hints, linkAction, action, className }) {
783
+ return /* @__PURE__ */ jsxs7(
784
+ "div",
785
+ {
786
+ className: cn(
787
+ "flex flex-col items-center justify-center gap-4 px-8 py-16 text-center",
788
+ className
789
+ ),
790
+ children: [
791
+ icon && /* @__PURE__ */ jsx13("div", { className: "flex h-14 w-14 items-center justify-center text-muted-foreground/40 [&_svg]:h-9 [&_svg]:w-9 [&_svg]:stroke-[1.35]", children: icon }),
792
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
793
+ /* @__PURE__ */ jsx13("h3", { className: "text-base font-semibold text-foreground", children: title }),
794
+ description && /* @__PURE__ */ jsx13("p", { className: "max-w-sm text-sm text-muted-foreground leading-relaxed", children: description })
795
+ ] }),
796
+ hints && hints.length > 0 && /* @__PURE__ */ jsx13("ul", { className: "mt-1 flex flex-col gap-1.5 text-left", children: hints.map((hint) => /* @__PURE__ */ jsxs7("li", { className: "flex items-start gap-2.5 text-sm text-muted-foreground", children: [
797
+ /* @__PURE__ */ jsx13("span", { className: "mt-[7px] h-1.5 w-1.5 shrink-0 rounded-full bg-primary opacity-80" }),
798
+ /* @__PURE__ */ jsx13("span", { children: hint })
799
+ ] }, hint)) }),
800
+ linkAction && /* @__PURE__ */ jsx13("div", { className: "mt-3", children: linkAction.href ? /* @__PURE__ */ jsx13(Button, { asChild: true, variant: "outline", size: "sm", children: /* @__PURE__ */ jsx13(
801
+ "a",
802
+ {
803
+ href: linkAction.href,
804
+ target: "_blank",
805
+ rel: "noopener noreferrer",
806
+ children: linkAction.label
807
+ }
808
+ ) }) : /* @__PURE__ */ jsx13(
809
+ Button,
810
+ {
811
+ type: "button",
812
+ variant: "outline",
813
+ size: "sm",
814
+ onClick: linkAction.onClick,
815
+ children: linkAction.label
816
+ }
817
+ ) }),
818
+ action && /* @__PURE__ */ jsx13(
819
+ Button,
820
+ {
821
+ type: "button",
822
+ variant: "ghost",
823
+ size: "sm",
824
+ onClick: action.onClick,
825
+ className: "mt-2 text-muted-foreground hover:text-foreground",
826
+ children: action.label
827
+ }
828
+ )
829
+ ]
830
+ }
831
+ );
832
+ }
833
+
834
+ // src/components/section-card.tsx
835
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
836
+ function SectionCard({
837
+ icon,
838
+ title,
839
+ description,
840
+ action,
841
+ children
842
+ }) {
843
+ return /* @__PURE__ */ jsxs8("section", { className: "ui-panel min-w-0 overflow-hidden", children: [
844
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between gap-4 border-b border-ui-line px-5 py-4", children: [
845
+ /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 items-center gap-2.5", children: [
846
+ icon && /* @__PURE__ */ jsx14("span", { className: "shrink-0 text-ui-subtle", children: icon }),
847
+ /* @__PURE__ */ jsxs8("div", { className: "min-w-0", children: [
848
+ /* @__PURE__ */ jsx14("h2", { className: "text-[11px] font-semibold uppercase tracking-[0.14em] text-ui-default", children: title }),
849
+ description && /* @__PURE__ */ jsx14("p", { className: "mt-0.5 truncate text-xs text-ui-subtle", children: description })
850
+ ] })
851
+ ] }),
852
+ action && /* @__PURE__ */ jsx14("div", { className: "shrink-0", children: action })
853
+ ] }),
854
+ children
855
+ ] });
856
+ }
857
+
858
+ // src/components/copy-button.tsx
859
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
860
+ import { Check as Check2, Copy } from "lucide-react";
861
+
862
+ // src/lib/constants.ts
863
+ var UI_DURATION_TOOLTIP = 1500;
864
+
865
+ // src/components/copy-button.tsx
866
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
867
+ function CopyButton({
868
+ value,
869
+ label = "Copy",
870
+ className
871
+ }) {
872
+ const [copied, setCopied] = useState2(false);
873
+ const timer = useRef2(null);
874
+ useEffect2(() => () => {
875
+ if (timer.current !== null) window.clearTimeout(timer.current);
876
+ }, []);
877
+ const copy = async () => {
878
+ try {
879
+ await navigator.clipboard.writeText(value);
880
+ setCopied(true);
881
+ if (timer.current !== null) window.clearTimeout(timer.current);
882
+ timer.current = window.setTimeout(() => setCopied(false), UI_DURATION_TOOLTIP);
883
+ } catch {
884
+ }
885
+ };
886
+ return /* @__PURE__ */ jsxs9(
887
+ "button",
888
+ {
889
+ type: "button",
890
+ onClick: copy,
891
+ "aria-label": copied ? "Copied" : label,
892
+ className: cn(
893
+ "inline-flex shrink-0 items-center gap-1 rounded border border-ui-line px-1.5 py-0.5",
894
+ "text-[10px] font-medium transition-colors",
895
+ copied ? "text-emerald-500" : "text-ui-subtle hover:text-foreground",
896
+ className
897
+ ),
898
+ children: [
899
+ copied ? /* @__PURE__ */ jsx15(Check2, { size: 10 }) : /* @__PURE__ */ jsx15(Copy, { size: 10 }),
900
+ copied ? "Copied" : label
901
+ ]
902
+ }
903
+ );
904
+ }
905
+
906
+ // src/components/bar-sparkline.tsx
907
+ import { useMemo } from "react";
908
+ import { jsx as jsx16 } from "react/jsx-runtime";
909
+ function bucketize(data, bars) {
910
+ const out = Array(bars).fill(0);
911
+ if (data.length === 0) return out;
912
+ if (data.length >= bars) {
913
+ const size = data.length / bars;
914
+ for (let i = 0; i < bars; i++) {
915
+ const start = Math.floor(i * size);
916
+ const end = Math.floor((i + 1) * size);
917
+ out[i] = data.slice(start, end).reduce((sum, v) => sum + v, 0);
918
+ }
919
+ } else {
920
+ for (let i = 0; i < bars; i++) {
921
+ out[i] = data[Math.floor(i * data.length / bars)];
922
+ }
923
+ }
924
+ return out;
925
+ }
926
+ var BASELINE_PCT = 32;
927
+ function BarSparkline({ data, color, bars = 8, className }) {
928
+ const buckets = useMemo(() => bucketize(data, bars), [data, bars]);
929
+ const max = Math.max(...buckets, 1);
930
+ return /* @__PURE__ */ jsx16("div", { className: cn("flex h-12 items-end justify-end gap-[3px]", className), "aria-hidden": "true", children: buckets.map((value, i) => /* @__PURE__ */ jsx16(
931
+ "div",
932
+ {
933
+ className: "w-[5px] rounded-[2px] transition-[height] duration-500",
934
+ style: {
935
+ height: `${BASELINE_PCT + value / max * (100 - BASELINE_PCT)}%`,
936
+ background: `linear-gradient(to top, ${color}99, ${color})`
937
+ }
938
+ },
939
+ i
940
+ )) });
941
+ }
942
+
943
+ // src/components/github-mark.tsx
944
+ import { jsx as jsx17 } from "react/jsx-runtime";
945
+ function GithubMark({ size = 16, className }) {
946
+ return /* @__PURE__ */ jsx17(
947
+ "svg",
948
+ {
949
+ width: size,
950
+ height: size,
951
+ viewBox: "0 0 24 24",
952
+ fill: "currentColor",
953
+ className,
954
+ "aria-hidden": "true",
955
+ children: /* @__PURE__ */ jsx17("path", { d: "M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.11.79-.25.79-.55 0-.27-.01-1.17-.02-2.12-3.2.7-3.87-1.36-3.87-1.36-.52-1.33-1.28-1.68-1.28-1.68-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.19 1.76 1.19 1.03 1.76 2.69 1.25 3.34.96.1-.75.4-1.25.72-1.54-2.55-.29-5.24-1.28-5.24-5.68 0-1.26.45-2.28 1.19-3.09-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.17 1.18a11 11 0 0 1 2.89-.39c.98 0 1.97.13 2.89.39 2.2-1.49 3.16-1.18 3.16-1.18.63 1.59.24 2.76.12 3.05.74.81 1.19 1.83 1.19 3.09 0 4.41-2.69 5.38-5.25 5.67.41.35.77 1.05.77 2.12 0 1.53-.01 2.76-.01 3.14 0 .3.2.66.8.55A11.51 11.51 0 0 0 23.5 12C23.5 5.65 18.35.5 12 .5Z" })
956
+ }
957
+ );
958
+ }
959
+
960
+ // src/components/load-error.tsx
961
+ import { AlertTriangle as AlertTriangle3, RefreshCw } from "lucide-react";
962
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
963
+ function LoadError({
964
+ title = "Couldn't load data",
965
+ detail,
966
+ hint = "Check your connection, then try again. If this keeps happening, the server may be unreachable.",
967
+ onRetry,
968
+ retrying,
969
+ className
970
+ }) {
971
+ return /* @__PURE__ */ jsx18(
972
+ "section",
973
+ {
974
+ role: "alert",
975
+ className: cn(
976
+ "ui-font-sans rounded-lg border border-ui-line bg-white p-3.5 dark:border-[oklch(0.27_0_0)] dark:bg-black sm:p-4",
977
+ className
978
+ ),
979
+ children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-6", children: [
980
+ /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 items-start gap-3", children: [
981
+ /* @__PURE__ */ jsx18("span", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-red-500/10 text-red-600 dark:text-red-400", children: /* @__PURE__ */ jsx18(AlertTriangle3, { size: 15, strokeWidth: 2 }) }),
982
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
983
+ /* @__PURE__ */ jsx18("h2", { className: "text-[13px] font-medium text-ui-default", children: title }),
984
+ /* @__PURE__ */ jsx18("p", { className: "mt-0.5 text-xs leading-relaxed text-ui-subtle", children: hint }),
985
+ detail && /* @__PURE__ */ jsx18("code", { className: "ui-well ui-font-mono mt-2 inline-block max-w-full truncate rounded-[5px] px-2 py-1 text-[11px] text-ui-subtle", children: detail })
986
+ ] })
987
+ ] }),
988
+ onRetry && /* @__PURE__ */ jsx18(
989
+ Button,
990
+ {
991
+ variant: "secondary",
992
+ size: "sm",
993
+ onClick: onRetry,
994
+ disabled: retrying,
995
+ icon: /* @__PURE__ */ jsx18(RefreshCw, { size: 13, className: retrying ? "animate-spin" : "" }),
996
+ className: "w-full shrink-0 sm:w-auto",
997
+ children: "Retry"
998
+ }
999
+ )
1000
+ ] })
1001
+ }
1002
+ );
1003
+ }
1004
+
1005
+ // src/components/chart-primitives.tsx
1006
+ import { Children } from "react";
1007
+ import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
1008
+ function CardDots() {
1009
+ return /* @__PURE__ */ jsx19(
1010
+ "div",
1011
+ {
1012
+ "aria-hidden": true,
1013
+ className: "pointer-events-none absolute inset-0 opacity-[0.35]",
1014
+ style: {
1015
+ backgroundImage: "radial-gradient(circle, var(--ui-line) 1px, transparent 1px)",
1016
+ backgroundSize: "18px 18px"
1017
+ }
1018
+ }
1019
+ );
1020
+ }
1021
+ function GraphShell({
1022
+ title,
1023
+ icon,
1024
+ legend,
1025
+ children,
1026
+ className = ""
1027
+ }) {
1028
+ return /* @__PURE__ */ jsxs11(LayerCard, { className: cn("relative flex flex-col overflow-hidden", className), children: [
1029
+ /* @__PURE__ */ jsx19(CardDots, {}),
1030
+ /* @__PURE__ */ jsxs11("div", { className: "relative flex items-center gap-2 px-4 pt-4 sm:px-5 sm:pt-5", children: [
1031
+ icon && /* @__PURE__ */ jsx19("span", { className: "shrink-0 text-ui-subtle", children: icon }),
1032
+ /* @__PURE__ */ jsx19("h3", { className: "truncate text-[11px] font-semibold uppercase tracking-[0.14em] text-ui-default", children: title })
1033
+ ] }),
1034
+ legend && /* @__PURE__ */ jsx19("div", { className: "relative flex flex-wrap items-center gap-x-4 gap-y-1.5 px-4 pt-3 sm:px-5", children: legend }),
1035
+ /* @__PURE__ */ jsx19("div", { className: "relative flex flex-1 flex-col", children })
1036
+ ] });
1037
+ }
1038
+ function LegendChip({
1039
+ color,
1040
+ hatched,
1041
+ dashed,
1042
+ label
1043
+ }) {
1044
+ return /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-1.5 text-xs text-ui-subtle", children: [
1045
+ dashed ? /* @__PURE__ */ jsx19(
1046
+ "span",
1047
+ {
1048
+ className: "h-0 w-3.5 shrink-0 border-t-2 border-dashed",
1049
+ style: { borderColor: color }
1050
+ }
1051
+ ) : /* @__PURE__ */ jsx19(
1052
+ "span",
1053
+ {
1054
+ className: "h-2.5 w-2.5 shrink-0 rounded-[3px]",
1055
+ style: hatched ? {
1056
+ backgroundImage: "repeating-linear-gradient(45deg, var(--ui-subtle) 0 1.5px, transparent 1.5px 3.5px)",
1057
+ backgroundColor: "color-mix(in oklch, var(--ui-fill) 60%, transparent)"
1058
+ } : { backgroundColor: color }
1059
+ }
1060
+ ),
1061
+ label
1062
+ ] });
1063
+ }
1064
+ function ChartDefs({ isDark }) {
1065
+ const hatch = isDark ? "rgba(228,228,231,0.5)" : "rgba(63,63,70,0.4)";
1066
+ const hatchBg = isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.04)";
1067
+ return /* @__PURE__ */ jsxs11("defs", { children: [
1068
+ /* @__PURE__ */ jsxs11("pattern", { id: "hatchGray", patternUnits: "userSpaceOnUse", width: "5", height: "5", patternTransform: "rotate(45)", children: [
1069
+ /* @__PURE__ */ jsx19("rect", { width: "5", height: "5", fill: hatchBg }),
1070
+ /* @__PURE__ */ jsx19("line", { x1: "0", y1: "0", x2: "0", y2: "5", stroke: hatch, strokeWidth: "1.4" })
1071
+ ] }),
1072
+ /* @__PURE__ */ jsxs11("linearGradient", { id: "blueBar", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1073
+ /* @__PURE__ */ jsx19("stop", { offset: "0%", stopColor: "#60a5fa" }),
1074
+ /* @__PURE__ */ jsx19("stop", { offset: "100%", stopColor: "#2563eb" })
1075
+ ] }),
1076
+ /* @__PURE__ */ jsxs11("linearGradient", { id: "amberFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1077
+ /* @__PURE__ */ jsx19("stop", { offset: "0%", stopColor: isDark ? "#f59e0b" : "#d97706", stopOpacity: 0.16 }),
1078
+ /* @__PURE__ */ jsx19("stop", { offset: "100%", stopColor: isDark ? "#f59e0b" : "#d97706", stopOpacity: 0.02 })
1079
+ ] })
1080
+ ] });
1081
+ }
1082
+ var METER_ROW_PX = 20;
1083
+ var METER_GAP_PX = 14;
1084
+ function MeterList({ visible, children }) {
1085
+ const scrolls = Children.count(children) > visible;
1086
+ return /* @__PURE__ */ jsx19("div", { className: "px-4 pb-5 pt-4 sm:px-5 sm:pb-6 sm:pt-5", children: /* @__PURE__ */ jsx19(
1087
+ "div",
1088
+ {
1089
+ className: cn("space-y-3.5", scrolls && "overflow-y-auto pr-3"),
1090
+ style: scrolls ? { maxHeight: visible * METER_ROW_PX + (visible - 1) * METER_GAP_PX } : void 0,
1091
+ children
1092
+ }
1093
+ ) });
1094
+ }
1095
+ function TickMeter({
1096
+ label,
1097
+ value,
1098
+ max,
1099
+ color,
1100
+ valueLabel
1101
+ }) {
1102
+ const SEGMENTS = 26;
1103
+ const filled = value > 0 ? Math.max(1, Math.round(value / Math.max(max, 1) * SEGMENTS)) : 0;
1104
+ return /* @__PURE__ */ jsxs11("div", { className: "flex h-5 items-center gap-3", children: [
1105
+ /* @__PURE__ */ jsx19("span", { className: "w-28 shrink-0 truncate text-[13px] font-medium text-ui-default", title: label, children: label }),
1106
+ /* @__PURE__ */ jsx19("div", { className: "flex h-4 flex-1 items-stretch gap-[2.5px]", "aria-hidden": true, children: Array.from({ length: SEGMENTS }).map((_, i) => /* @__PURE__ */ jsx19(
1107
+ "span",
1108
+ {
1109
+ className: "min-w-[2px] flex-1 rounded-[1px]",
1110
+ style: { backgroundColor: i < filled ? color : "var(--ui-fill)" }
1111
+ },
1112
+ i
1113
+ )) }),
1114
+ /* @__PURE__ */ jsx19("span", { className: "ui-font-mono w-14 shrink-0 text-right text-xs tabular-nums text-ui-default", children: valueLabel })
1115
+ ] });
1116
+ }
1117
+ export {
1118
+ Alert,
1119
+ Badge,
1120
+ BarSparkline,
1121
+ Button,
1122
+ CardDots,
1123
+ ChartDefs,
1124
+ ConfirmDialog,
1125
+ CopyButton,
1126
+ EmptyState,
1127
+ GithubMark,
1128
+ GraphShell,
1129
+ Input,
1130
+ LayerCard,
1131
+ LegendChip,
1132
+ LinkButton,
1133
+ LoadError,
1134
+ MeterList,
1135
+ SectionCard,
1136
+ Select,
1137
+ Skeleton,
1138
+ Switch,
1139
+ Text,
1140
+ TickMeter,
1141
+ badgeVariants,
1142
+ buttonVariants
1143
+ };
1144
+ //# sourceMappingURL=index.js.map