@usetheo/ui 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,53 @@
1
+ import { Command as CommandPrimitive } from "cmdk";
2
+ import type { ComponentPropsWithoutRef, HTMLAttributes, ReactNode } from "react";
3
+ interface ComboboxProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> {
4
+ /** Selected value (controlled). */
5
+ value?: string;
6
+ onValueChange?: (value: string) => void;
7
+ /** Listbox visibility (controlled). */
8
+ open?: boolean;
9
+ defaultOpen?: boolean;
10
+ onOpenChange?: (open: boolean) => void;
11
+ /** Set false to disable cmdk's internal filter (async mode — consumer filters). */
12
+ shouldFilter?: boolean;
13
+ children: ReactNode;
14
+ }
15
+ type ComboboxInputProps = ComponentPropsWithoutRef<typeof CommandPrimitive.Input>;
16
+ interface ComboboxContentProps extends HTMLAttributes<HTMLDivElement> {
17
+ /** Async fetch in flight: shows the loading slot and hides items/empty. */
18
+ loading?: boolean;
19
+ }
20
+ type ComboboxItemProps = ComponentPropsWithoutRef<typeof CommandPrimitive.Item>;
21
+ declare const Combobox: import("react").ForwardRefExoticComponent<ComboboxProps & import("react").RefAttributes<HTMLDivElement>> & {
22
+ Input: import("react").ForwardRefExoticComponent<Omit<Omit<Pick<Pick<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "key" | keyof import("react").InputHTMLAttributes<HTMLInputElement>> & {
23
+ ref?: React.Ref<HTMLInputElement>;
24
+ } & {
25
+ asChild?: boolean;
26
+ }, "asChild" | "key" | keyof import("react").InputHTMLAttributes<HTMLInputElement>>, "type" | "value" | "onChange"> & {
27
+ value?: string;
28
+ onValueChange?: (search: string) => void;
29
+ } & import("react").RefAttributes<HTMLInputElement>, "ref"> & import("react").RefAttributes<HTMLInputElement>>;
30
+ Content: import("react").ForwardRefExoticComponent<ComboboxContentProps & import("react").RefAttributes<HTMLDivElement>>;
31
+ Item: import("react").ForwardRefExoticComponent<Omit<{
32
+ children?: React.ReactNode;
33
+ } & Omit<Pick<Pick<import("react").DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof HTMLAttributes<HTMLDivElement>> & {
34
+ ref?: React.Ref<HTMLDivElement>;
35
+ } & {
36
+ asChild?: boolean;
37
+ }, "asChild" | "key" | keyof HTMLAttributes<HTMLDivElement>>, "disabled" | "value" | "onSelect"> & {
38
+ disabled?: boolean;
39
+ onSelect?: (value: string) => void;
40
+ value?: string;
41
+ keywords?: string[];
42
+ forceMount?: boolean;
43
+ } & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
44
+ Empty: import("react").ForwardRefExoticComponent<Omit<{
45
+ children?: React.ReactNode;
46
+ } & Pick<Pick<import("react").DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof HTMLAttributes<HTMLDivElement>> & {
47
+ ref?: React.Ref<HTMLDivElement>;
48
+ } & {
49
+ asChild?: boolean;
50
+ }, "asChild" | "key" | keyof HTMLAttributes<HTMLDivElement>> & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
51
+ };
52
+ export { Combobox };
53
+ export type { ComboboxProps, ComboboxContentProps, ComboboxInputProps, ComboboxItemProps };
@@ -0,0 +1 @@
1
+ export { Combobox, type ComboboxContentProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxProps, } from "./combobox.js";
@@ -0,0 +1,33 @@
1
+ import type { HTMLAttributes } from "react";
2
+ /**
3
+ * DescriptionList — semantic key/value pairs on native `dl/dt/dd`.
4
+ *
5
+ * Layouts: `vertical` (default — stacked groups) and `horizontal` (two-column
6
+ * grid: terms in a fixed max-content column, details beside them; the Item
7
+ * wrapper uses `display: contents` so dt/dd participate in the root grid).
8
+ * `dense` tightens the gaps for crowded detail panels.
9
+ *
10
+ * <DescriptionList layout="horizontal">
11
+ * <DescriptionList.Item>
12
+ * <DescriptionList.Term>Status</DescriptionList.Term>
13
+ * <DescriptionList.Detail><Badge>live</Badge></DescriptionList.Detail>
14
+ * </DescriptionList.Item>
15
+ * </DescriptionList>
16
+ *
17
+ * One Term per Item; multiple Details per Term are valid HTML and supported.
18
+ * Composing dd without a preceding dt is the consumer's responsibility
19
+ * (invalid HTML — same contract as Breadcrumb.Page placement).
20
+ */
21
+ interface DescriptionListProps extends HTMLAttributes<HTMLDListElement> {
22
+ /** vertical (default): stacked groups. horizontal: term column + detail column. */
23
+ layout?: "vertical" | "horizontal";
24
+ /** Compact spacing for dense detail panels. */
25
+ dense?: boolean;
26
+ }
27
+ declare const DescriptionList: import("react").ForwardRefExoticComponent<DescriptionListProps & import("react").RefAttributes<HTMLDListElement>> & {
28
+ Item: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
29
+ Term: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & import("react").RefAttributes<HTMLElement>>;
30
+ Detail: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & import("react").RefAttributes<HTMLElement>>;
31
+ };
32
+ export { DescriptionList };
33
+ export type { DescriptionListProps };
@@ -0,0 +1 @@
1
+ export { DescriptionList, type DescriptionListProps } from "./description-list.js";
@@ -0,0 +1 @@
1
+ export { JsonViewer, type JsonViewerProps } from "./json-viewer.js";
@@ -0,0 +1,32 @@
1
+ import type { HTMLAttributes } from "react";
2
+ /**
3
+ * JsonViewer — read-only collapsible JSON tree, dependency-free.
4
+ *
5
+ * Collapse: `collapsed` mirrors the SOTA contract — `true` collapses every
6
+ * node, a number collapses everything at depth >= N (root is depth 0).
7
+ * Collapsed subtrees are NOT rendered (lazy): that is the performance guard —
8
+ * a huge payload fully expanded is the consumer's responsibility (ADR D1);
9
+ * prefer `collapsed={1}` for large payloads.
10
+ *
11
+ * Safety: circular references render a "[Circular]" marker (and serialize as
12
+ * such on copy) instead of overflowing the stack. Copy limitation: the
13
+ * serializer conservatively marks REPEATED (shared, non-circular) references
14
+ * as "[Circular]" too — output is always JSON.parse-able — the studied SOTA reference
15
+ * does not handle this. BigInt renders with the `n` suffix; NaN/Infinity
16
+ * follow JSON semantics on copy (null).
17
+ *
18
+ * <JsonViewer value={eventPayload} collapsed={1} enableCopy />
19
+ */
20
+ interface JsonViewerProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
21
+ /** Data to render. Any value — objects, arrays, primitives, BigInt, Date. */
22
+ value: unknown;
23
+ /** true = all collapsed; number = collapse at depth >= N. Default: all expanded. */
24
+ collapsed?: boolean | number;
25
+ /** Truncate strings longer than this (click to reveal). Default 60. */
26
+ shortenTextAfterLength?: number;
27
+ /** Show a copy button on the root and on object/array nodes. */
28
+ enableCopy?: boolean;
29
+ }
30
+ declare const JsonViewer: import("react").ForwardRefExoticComponent<JsonViewerProps & import("react").RefAttributes<HTMLDivElement>>;
31
+ export { JsonViewer };
32
+ export type { JsonViewerProps };
@@ -0,0 +1 @@
1
+ export { Slider, type SliderMark, type SliderProps } from "./slider.js";
@@ -0,0 +1,24 @@
1
+ import * as SliderPrimitive from "@radix-ui/react-slider";
2
+ import type { ComponentPropsWithoutRef, ReactNode } from "react";
3
+ /**
4
+ * Slider — range input primitive over Radix Slider.
5
+ *
6
+ * Single thumb: `defaultValue={[5]}`. Range: `defaultValue={[20, 80]}` (one
7
+ * thumb per array entry). `marks` renders labelled, clickable points over the
8
+ * track (Mantine-shaped `{value, label?}`); clicking a mark sets the value in
9
+ * single mode and is a no-op in range mode (which thumb to move is ambiguous).
10
+ *
11
+ * <Slider aria-label="Top K" min={1} max={100} defaultValue={[5]}
12
+ * marks={[{ value: 1 }, { value: 50 }, { value: 100 }]} />
13
+ */
14
+ interface SliderMark {
15
+ value: number;
16
+ label?: ReactNode;
17
+ }
18
+ interface SliderProps extends ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {
19
+ /** Labelled, clickable points rendered over the track. Values outside [min, max] are skipped. */
20
+ marks?: SliderMark[];
21
+ }
22
+ declare const Slider: import("react").ForwardRefExoticComponent<SliderProps & import("react").RefAttributes<HTMLSpanElement>>;
23
+ export { Slider };
24
+ export type { SliderMark, SliderProps };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,10 @@ export { cn } from "./lib/cn.js";
2
2
  export { Button, buttonVariants, type ButtonProps } from "./components/primitives/button/index.js";
3
3
  export { Badge, badgeVariants, type BadgeProps } from "./components/primitives/badge/index.js";
4
4
  export { Breadcrumb, type BreadcrumbLinkProps, } from "./components/primitives/breadcrumb/index.js";
5
+ export { DescriptionList, type DescriptionListProps, } from "./components/primitives/description-list/index.js";
6
+ export { JsonViewer, type JsonViewerProps } from "./components/primitives/json-viewer/index.js";
7
+ export { Combobox, type ComboboxContentProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxProps, } from "./components/primitives/combobox/index.js";
8
+ export { Slider, type SliderMark, type SliderProps, } from "./components/primitives/slider/index.js";
5
9
  export { UpdateBanner, type UpdateBannerProps, } from "./components/primitives/update-banner/index.js";
6
10
  export { Card } from "./components/primitives/card/index.js";
7
11
  export { Input, type InputProps } from "./components/primitives/input/index.js";
package/dist/index.js CHANGED
@@ -2,9 +2,11 @@ import { clsx } from 'clsx';
2
2
  import { extendTailwindMerge } from 'tailwind-merge';
3
3
  import { Slot } from '@radix-ui/react-slot';
4
4
  import { cva } from 'class-variance-authority';
5
- import { forwardRef, createContext, useId, Children, isValidElement, cloneElement, Fragment as Fragment$1, useContext, useEffect, useState, useRef, useCallback, createElement, useMemo } from 'react';
5
+ import { forwardRef, useState, useRef, useEffect, useCallback, createContext, useId, useMemo, Children, isValidElement, cloneElement, Fragment as Fragment$1, useContext, createElement } from 'react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import { ArrowUpCircle, X, AlertCircle, ChevronDown, ChevronUp, Check, Minus, Circle, ChevronRight, ChevronsUpDown, Copy, TrendingDown, TrendingUp, ArrowUpRight, Loader2, TriangleAlert, CheckCircle2, Info, ChevronsLeft, ChevronLeft, ChevronsRight, Search, Filter, GitCommit, GitBranch, Activity, Plus, Lock, EyeOff, Eye, Trash2, GitPullRequest, Server, ExternalLink, Globe, ShieldCheck, ShieldX, Clock, RotateCcw, ArrowDownLeft, MoreHorizontal } from 'lucide-react';
7
+ import { Check, X, Copy, Loader2, ArrowUpCircle, AlertCircle, ChevronDown, ChevronUp, Minus, Circle, ChevronRight, ChevronsUpDown, TrendingDown, TrendingUp, ArrowUpRight, TriangleAlert, CheckCircle2, Info, ChevronsLeft, ChevronLeft, ChevronsRight, Search, Filter, GitCommit, GitBranch, Activity, Plus, Lock, EyeOff, Eye, Trash2, GitPullRequest, Server, ExternalLink, Globe, ShieldCheck, ShieldX, Clock, RotateCcw, ArrowDownLeft, MoreHorizontal } from 'lucide-react';
8
+ import { Command, useCommandState } from 'cmdk';
9
+ import * as SliderPrimitive from '@radix-ui/react-slider';
8
10
  import * as DialogPrimitive from '@radix-ui/react-dialog';
9
11
  import * as TabsPrimitive from '@radix-ui/react-tabs';
10
12
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
@@ -17,7 +19,6 @@ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
17
19
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
18
20
  import * as SwitchPrimitive from '@radix-ui/react-switch';
19
21
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
20
- import { Command } from 'cmdk';
21
22
 
22
23
  // src/lib/cn.ts
23
24
  var twMerge = extendTailwindMerge({
@@ -286,6 +287,657 @@ var Breadcrumb = Object.assign(Root, {
286
287
  Separator,
287
288
  Ellipsis
288
289
  });
290
+ function sub2(tag, slot, displayName, baseClass) {
291
+ const Component = forwardRef(
292
+ ({ className, children, ...props }, ref) => createElement(
293
+ tag,
294
+ { "data-slot": slot, ref, className: cn(baseClass, className), ...props },
295
+ children
296
+ )
297
+ );
298
+ Component.displayName = displayName;
299
+ return Component;
300
+ }
301
+ var Root2 = forwardRef(
302
+ ({ className, layout = "vertical", dense, ...props }, ref) => /* @__PURE__ */ jsx(
303
+ "dl",
304
+ {
305
+ "data-slot": "description-list",
306
+ "data-layout": layout,
307
+ "data-dense": dense ? "true" : void 0,
308
+ ref,
309
+ className: cn(
310
+ "text-body-sm",
311
+ layout === "vertical" && (dense ? "grid gap-2" : "grid gap-4"),
312
+ layout === "horizontal" && "grid grid-cols-[max-content_1fr] items-baseline [&>div]:contents [&_dd]:col-start-2",
313
+ layout === "horizontal" && (dense ? "gap-x-4 gap-y-1.5" : "gap-x-6 gap-y-3"),
314
+ className
315
+ ),
316
+ ...props
317
+ }
318
+ )
319
+ );
320
+ Root2.displayName = "DescriptionList";
321
+ var Item2 = sub2(
322
+ "div",
323
+ "description-list-item",
324
+ "DescriptionList.Item",
325
+ "grid gap-1"
326
+ );
327
+ var Term = sub2(
328
+ "dt",
329
+ "description-list-term",
330
+ "DescriptionList.Term",
331
+ "font-medium text-muted-foreground"
332
+ );
333
+ var Detail = sub2(
334
+ "dd",
335
+ "description-list-detail",
336
+ "DescriptionList.Detail",
337
+ "m-0 text-foreground"
338
+ );
339
+ var DescriptionList = Object.assign(Root2, { Item: Item2, Term, Detail });
340
+ var VARIANT = {
341
+ ghost: "hover:bg-muted",
342
+ outline: "border border-border/60 rounded-md"
343
+ };
344
+ var SIZE = {
345
+ sm: "px-2 py-1 text-label",
346
+ md: "px-2.5 py-1.5 text-body-sm"
347
+ };
348
+ var CopyButton = forwardRef(
349
+ ({
350
+ className,
351
+ value,
352
+ label,
353
+ variant = "ghost",
354
+ size = "sm",
355
+ onCopied,
356
+ feedbackDuration = 1500,
357
+ ...props
358
+ }, ref) => {
359
+ const [state, setState] = useState("idle");
360
+ const timerRef = useRef(null);
361
+ useEffect(() => {
362
+ return () => {
363
+ if (timerRef.current !== null) {
364
+ clearTimeout(timerRef.current);
365
+ }
366
+ };
367
+ }, []);
368
+ const scheduleRevert = useCallback(() => {
369
+ if (timerRef.current !== null) {
370
+ clearTimeout(timerRef.current);
371
+ }
372
+ timerRef.current = setTimeout(() => {
373
+ setState("idle");
374
+ timerRef.current = null;
375
+ }, feedbackDuration);
376
+ }, [feedbackDuration]);
377
+ const handleClick = useCallback(() => {
378
+ if (state !== "idle") return;
379
+ if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
380
+ setState("failed");
381
+ scheduleRevert();
382
+ return;
383
+ }
384
+ navigator.clipboard.writeText(value).then(
385
+ () => {
386
+ setState("copied");
387
+ onCopied?.(value);
388
+ scheduleRevert();
389
+ },
390
+ () => {
391
+ setState("failed");
392
+ scheduleRevert();
393
+ }
394
+ );
395
+ }, [state, value, onCopied, scheduleRevert]);
396
+ const Icon2 = state === "copied" ? Check : state === "failed" ? X : Copy;
397
+ const liveMessage = state === "copied" ? "Copied to clipboard" : state === "failed" ? "Copy failed" : "";
398
+ const labelText = label !== void 0 ? state === "copied" ? "Copied!" : state === "failed" ? "Failed" : label : null;
399
+ return /* @__PURE__ */ jsxs(
400
+ "button",
401
+ {
402
+ "data-slot": "copy-button",
403
+ ref,
404
+ type: "button",
405
+ onClick: handleClick,
406
+ "data-state": state,
407
+ className: cn(
408
+ "inline-flex items-center gap-1.5",
409
+ "font-sans transition-colors",
410
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card",
411
+ VARIANT[variant],
412
+ SIZE[size],
413
+ className
414
+ ),
415
+ ...props,
416
+ children: [
417
+ /* @__PURE__ */ jsx(
418
+ Icon2,
419
+ {
420
+ "aria-hidden": "true",
421
+ className: cn(
422
+ "size-3.5 shrink-0 transition-opacity duration-200",
423
+ state === "copied" && "text-success",
424
+ state === "failed" && "text-destructive"
425
+ )
426
+ }
427
+ ),
428
+ labelText !== null ? /* @__PURE__ */ jsx("span", { children: labelText }) : null,
429
+ /* @__PURE__ */ jsx("span", { className: "sr-only", "aria-live": "polite", children: liveMessage })
430
+ ]
431
+ }
432
+ );
433
+ }
434
+ );
435
+ CopyButton.displayName = "CopyButton";
436
+ var PATH_SEP = "";
437
+ var EMPTY_CHAIN = { has: () => false };
438
+ function isPlainContainer(value) {
439
+ return typeof value === "object" && value !== null && !(value instanceof Date);
440
+ }
441
+ function safeStringify(value) {
442
+ const seen = /* @__PURE__ */ new WeakSet();
443
+ return JSON.stringify(
444
+ value,
445
+ (_key, entry) => {
446
+ if (typeof entry === "bigint") return `${entry}n`;
447
+ if (typeof entry === "object" && entry !== null) {
448
+ if (seen.has(entry)) return "[Circular]";
449
+ seen.add(entry);
450
+ }
451
+ return entry;
452
+ },
453
+ 2
454
+ );
455
+ }
456
+ function defaultExpanded(depth, collapsed) {
457
+ if (collapsed === true) return false;
458
+ if (typeof collapsed === "number") return depth < collapsed;
459
+ return true;
460
+ }
461
+ function PrimitiveValue({
462
+ value,
463
+ shortenAfter
464
+ }) {
465
+ const [revealed, setRevealed] = useState(false);
466
+ if (typeof value === "string") {
467
+ const shorten = !revealed && value.length > shortenAfter;
468
+ const text2 = shorten ? `${value.slice(0, shortenAfter)}\u2026` : `"${value}"`;
469
+ return /* @__PURE__ */ jsx(
470
+ "span",
471
+ {
472
+ "data-slot": "json-viewer-value",
473
+ "data-type": "string",
474
+ className: cn("text-success", shorten && "cursor-pointer underline decoration-dotted"),
475
+ onClick: shorten ? () => setRevealed(true) : void 0,
476
+ onKeyDown: shorten ? (e) => {
477
+ if (e.key === "Enter" || e.key === " ") {
478
+ e.preventDefault();
479
+ setRevealed(true);
480
+ }
481
+ } : void 0,
482
+ role: shorten ? "button" : void 0,
483
+ tabIndex: shorten ? 0 : void 0,
484
+ children: text2
485
+ }
486
+ );
487
+ }
488
+ let text;
489
+ let type = typeof value;
490
+ if (typeof value === "bigint") text = `${value}n`;
491
+ else if (value === null) {
492
+ text = "null";
493
+ type = "null";
494
+ } else if (value === void 0) text = "undefined";
495
+ else if (typeof value === "function") text = "\u0192";
496
+ else if (value instanceof Date) {
497
+ text = value.toISOString();
498
+ type = "date";
499
+ } else text = String(value);
500
+ return /* @__PURE__ */ jsx("span", { "data-slot": "json-viewer-value", "data-type": type, className: "text-info", children: text });
501
+ }
502
+ function JsonNode(props) {
503
+ const { nodeKey, value, path, depth, ancestors, viewer, expandedOverrides, onToggle } = props;
504
+ const copyValue = useMemo(
505
+ () => viewer.enableCopy && isPlainContainer(value) ? safeStringify(value) : "",
506
+ [value, viewer.enableCopy]
507
+ );
508
+ const keyLabel = nodeKey !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
509
+ /* @__PURE__ */ jsx("span", { "data-slot": "json-viewer-key", children: nodeKey === "" ? '""' : nodeKey }),
510
+ ":"
511
+ ] }) : null;
512
+ if (isPlainContainer(value) && ancestors.has(value)) {
513
+ return /* @__PURE__ */ jsxs("li", { "data-slot": "json-viewer-node", className: "flex items-baseline gap-1.5", children: [
514
+ keyLabel,
515
+ /* @__PURE__ */ jsx("span", { "data-slot": "json-viewer-value", "data-type": "circular", className: "text-warning", children: "[Circular]" })
516
+ ] });
517
+ }
518
+ if (!isPlainContainer(value)) {
519
+ return /* @__PURE__ */ jsxs("li", { "data-slot": "json-viewer-node", className: "flex items-baseline gap-1.5", children: [
520
+ keyLabel,
521
+ /* @__PURE__ */ jsx(PrimitiveValue, { value, shortenAfter: viewer.shortenTextAfterLength })
522
+ ] });
523
+ }
524
+ const isArray = Array.isArray(value);
525
+ const entries = isArray ? value.map((entry, index) => [String(index), entry]) : Object.entries(value);
526
+ if (entries.length === 0) {
527
+ return /* @__PURE__ */ jsxs("li", { "data-slot": "json-viewer-node", className: "flex items-baseline gap-1.5", children: [
528
+ keyLabel,
529
+ /* @__PURE__ */ jsx("span", { "data-slot": "json-viewer-value", "data-type": isArray ? "array" : "object", children: isArray ? "[]" : "{}" })
530
+ ] });
531
+ }
532
+ const expanded = expandedOverrides.get(path) ?? defaultExpanded(depth, viewer.collapsed);
533
+ const badge = isArray ? `[${entries.length}]` : `{${entries.length}}`;
534
+ return /* @__PURE__ */ jsxs("li", { "data-slot": "json-viewer-node", children: [
535
+ /* @__PURE__ */ jsxs("span", { className: "group/node flex items-baseline gap-1.5", children: [
536
+ /* @__PURE__ */ jsx(
537
+ "button",
538
+ {
539
+ type: "button",
540
+ "data-slot": "json-viewer-toggle",
541
+ "aria-expanded": expanded,
542
+ "aria-label": `Toggle ${nodeKey ?? "root"}`,
543
+ onClick: () => onToggle(path, !expanded),
544
+ className: "inline-flex size-4 shrink-0 translate-y-0.5 items-center justify-center rounded text-muted-foreground hover:text-foreground",
545
+ children: /* @__PURE__ */ jsx(
546
+ ChevronRight,
547
+ {
548
+ "aria-hidden": true,
549
+ className: cn("size-3.5 transition-transform", expanded && "rotate-90")
550
+ }
551
+ )
552
+ }
553
+ ),
554
+ keyLabel,
555
+ !expanded && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: badge }),
556
+ viewer.enableCopy && /* @__PURE__ */ jsx(
557
+ "span",
558
+ {
559
+ "data-slot": "json-viewer-copy",
560
+ className: "opacity-0 transition-opacity group-focus-within/node:opacity-100 group-hover/node:opacity-100",
561
+ children: /* @__PURE__ */ jsx(CopyButton, { value: copyValue, "aria-label": `Copy ${nodeKey ?? "JSON"}` })
562
+ }
563
+ )
564
+ ] }),
565
+ expanded && /* @__PURE__ */ jsx("ul", { className: "m-0 grid list-none gap-0.5 border-border/40 border-l pl-4", children: entries.map(([entryKey, entryValue]) => /* @__PURE__ */ jsx(
566
+ JsonNode,
567
+ {
568
+ nodeKey: entryKey,
569
+ value: entryValue,
570
+ path: path + PATH_SEP + entryKey,
571
+ depth: depth + 1,
572
+ ancestors: {
573
+ has: (candidate) => candidate === value || ancestors.has(candidate)
574
+ },
575
+ viewer,
576
+ expandedOverrides,
577
+ onToggle
578
+ },
579
+ entryKey
580
+ )) })
581
+ ] });
582
+ }
583
+ var JsonViewer = forwardRef(
584
+ ({ value, collapsed, shortenTextAfterLength = 60, enableCopy = false, className, ...props }, ref) => {
585
+ const [expandedOverrides, setExpandedOverrides] = useState(/* @__PURE__ */ new Map());
586
+ const onToggle = (path, next) => {
587
+ setExpandedOverrides((prev) => new Map(prev).set(path, next));
588
+ };
589
+ return /* @__PURE__ */ jsx(
590
+ "div",
591
+ {
592
+ "data-slot": "json-viewer",
593
+ ref,
594
+ className: cn("font-mono text-code-sm", className),
595
+ ...props,
596
+ children: /* @__PURE__ */ jsx("ul", { className: "m-0 grid list-none gap-0.5 p-0", children: /* @__PURE__ */ jsx(
597
+ JsonNode,
598
+ {
599
+ value,
600
+ path: "$",
601
+ depth: 0,
602
+ ancestors: EMPTY_CHAIN,
603
+ viewer: { collapsed, shortenTextAfterLength, enableCopy },
604
+ expandedOverrides,
605
+ onToggle
606
+ }
607
+ ) })
608
+ }
609
+ );
610
+ }
611
+ );
612
+ JsonViewer.displayName = "JsonViewer";
613
+ var inputVariants = cva(
614
+ [
615
+ "flex w-full rounded-md border border-input bg-card",
616
+ "text-foreground placeholder:text-muted-foreground",
617
+ "transition-[box-shadow,border-color] duration-base ease-out-soft",
618
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
619
+ "focus-visible:border-primary",
620
+ "disabled:cursor-not-allowed disabled:opacity-50",
621
+ "file:border-0 file:bg-transparent file:font-medium file:text-body-sm"
622
+ ],
623
+ {
624
+ variants: {
625
+ size: {
626
+ sm: "h-8 px-2.5 py-1 text-body-sm",
627
+ // md: density-tunable via CSS var. Comfortable (default) = 36px.
628
+ md: "h-[var(--theo-control-h,2.25rem)] px-[var(--theo-control-px,0.875rem)] py-1.5 text-body-sm",
629
+ lg: "h-11 px-4 py-2.5 text-body-md"
630
+ }
631
+ },
632
+ defaultVariants: { size: "md" }
633
+ }
634
+ );
635
+ var Input = forwardRef(
636
+ ({ className, type = "text", size, ...props }, ref) => /* @__PURE__ */ jsx(
637
+ "input",
638
+ {
639
+ "data-slot": "input",
640
+ "data-size": size,
641
+ ref,
642
+ type,
643
+ className: cn(inputVariants({ size }), className),
644
+ ...props
645
+ }
646
+ )
647
+ );
648
+ Input.displayName = "Input";
649
+ var ComboboxContext = createContext(null);
650
+ function composeRefs(local, forwarded) {
651
+ return (node) => {
652
+ local.current = node;
653
+ if (typeof forwarded === "function") forwarded(node);
654
+ else if (forwarded) forwarded.current = node;
655
+ };
656
+ }
657
+ function useComboboxContext(sub3) {
658
+ const ctx = useContext(ComboboxContext);
659
+ if (!ctx) throw new Error(`<Combobox.${sub3}> must be used inside <Combobox>`);
660
+ return ctx;
661
+ }
662
+ var Root3 = forwardRef(
663
+ ({
664
+ className,
665
+ children,
666
+ value,
667
+ onValueChange,
668
+ open: openProp,
669
+ defaultOpen = false,
670
+ onOpenChange,
671
+ shouldFilter = true,
672
+ "aria-label": ariaLabel,
673
+ ...props
674
+ }, ref) => {
675
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
676
+ const open = openProp ?? uncontrolledOpen;
677
+ const rootRef = useRef(null);
678
+ const listId = useId();
679
+ const setOpen = useCallback(
680
+ (next) => {
681
+ setUncontrolledOpen(next);
682
+ onOpenChange?.(next);
683
+ },
684
+ [onOpenChange]
685
+ );
686
+ const select = useCallback(
687
+ (next) => {
688
+ onValueChange?.(next);
689
+ setOpen(false);
690
+ },
691
+ [onValueChange, setOpen]
692
+ );
693
+ useEffect(() => {
694
+ if (!open) return;
695
+ const onMouseDown = (event) => {
696
+ if (rootRef.current && !rootRef.current.contains(event.target)) {
697
+ setOpen(false);
698
+ }
699
+ };
700
+ document.addEventListener("mousedown", onMouseDown);
701
+ return () => document.removeEventListener("mousedown", onMouseDown);
702
+ }, [open, setOpen]);
703
+ return /* @__PURE__ */ jsx(ComboboxContext.Provider, { value: { open, setOpen, value, select, listId }, children: /* @__PURE__ */ jsx(
704
+ "div",
705
+ {
706
+ "data-slot": "combobox",
707
+ ref: composeRefs(rootRef, ref),
708
+ className: cn("relative w-full", className),
709
+ ...props,
710
+ children: /* @__PURE__ */ jsx(Command, { label: ariaLabel, shouldFilter, children })
711
+ }
712
+ ) });
713
+ }
714
+ );
715
+ Root3.displayName = "Combobox";
716
+ var Input2 = forwardRef(
717
+ ({ className, onFocus, onKeyDown, onValueChange, ...props }, ref) => {
718
+ const { open, setOpen, listId } = useComboboxContext("Input");
719
+ const innerRef = useRef(null);
720
+ useEffect(() => {
721
+ const el = innerRef.current;
722
+ if (!el) return;
723
+ el.setAttribute("aria-expanded", String(open));
724
+ if (open) el.setAttribute("aria-controls", listId);
725
+ else el.removeAttribute("aria-controls");
726
+ });
727
+ return /* @__PURE__ */ jsx(
728
+ Command.Input,
729
+ {
730
+ "data-slot": "combobox-input",
731
+ ref: composeRefs(innerRef, ref),
732
+ className: cn(inputVariants({ size: "md" }), className),
733
+ onFocus: (event) => {
734
+ setOpen(true);
735
+ onFocus?.(event);
736
+ },
737
+ onKeyDown: (event) => {
738
+ if (event.key === "Escape") setOpen(false);
739
+ onKeyDown?.(event);
740
+ },
741
+ onValueChange: (search) => {
742
+ if (!open) setOpen(true);
743
+ onValueChange?.(search);
744
+ },
745
+ ...props
746
+ }
747
+ );
748
+ }
749
+ );
750
+ Input2.displayName = "Combobox.Input";
751
+ var Content = forwardRef(
752
+ ({ className, children, loading, ...props }, ref) => {
753
+ const { open, listId } = useComboboxContext("Content");
754
+ const resultCount = useCommandState((state) => state.filtered.count);
755
+ const listRef = useRef(null);
756
+ useEffect(() => {
757
+ const el = listRef.current;
758
+ if (!el) return;
759
+ el.setAttribute("id", listId);
760
+ if (resultCount === 0) {
761
+ el.setAttribute("role", "presentation");
762
+ el.removeAttribute("aria-label");
763
+ } else {
764
+ el.setAttribute("role", "listbox");
765
+ if (!el.getAttribute("aria-label")) el.setAttribute("aria-label", "Suggestions");
766
+ }
767
+ });
768
+ if (!open) return null;
769
+ return /* @__PURE__ */ jsx(
770
+ "div",
771
+ {
772
+ "data-slot": "combobox-content",
773
+ ref,
774
+ className: cn(
775
+ "absolute top-full z-50 mt-1 w-full rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md",
776
+ className
777
+ ),
778
+ ...props,
779
+ children: loading ? /* @__PURE__ */ jsxs(
780
+ "div",
781
+ {
782
+ "data-slot": "combobox-loading",
783
+ id: listId,
784
+ "aria-busy": "true",
785
+ className: "flex items-center justify-center gap-2 px-3 py-6 text-body-sm text-muted-foreground",
786
+ children: [
787
+ /* @__PURE__ */ jsx(Loader2, { "aria-hidden": true, className: "size-4 animate-spin" }),
788
+ "Loading\u2026"
789
+ ]
790
+ }
791
+ ) : /* @__PURE__ */ jsx(Command.List, { ref: listRef, className: "max-h-64 overflow-y-auto", children })
792
+ }
793
+ );
794
+ }
795
+ );
796
+ Content.displayName = "Combobox.Content";
797
+ var Item3 = forwardRef(
798
+ ({ className, children, value, onSelect, ...props }, ref) => {
799
+ const ctx = useComboboxContext("Item");
800
+ const selected = value !== void 0 && ctx.value === value;
801
+ return /* @__PURE__ */ jsxs(
802
+ Command.Item,
803
+ {
804
+ "data-slot": "combobox-item",
805
+ "data-selected-value": selected ? "true" : void 0,
806
+ ref,
807
+ value,
808
+ onSelect: (selectedValue) => {
809
+ ctx.select(selectedValue);
810
+ onSelect?.(selectedValue);
811
+ },
812
+ className: cn(
813
+ "flex cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-body-sm",
814
+ "data-[selected=true]:bg-accent/10 data-[selected=true]:text-foreground",
815
+ className
816
+ ),
817
+ ...props,
818
+ children: [
819
+ children,
820
+ /* @__PURE__ */ jsx(
821
+ Check,
822
+ {
823
+ "aria-hidden": true,
824
+ className: cn("ml-auto size-4", selected ? "opacity-100" : "opacity-0")
825
+ }
826
+ )
827
+ ]
828
+ }
829
+ );
830
+ }
831
+ );
832
+ Item3.displayName = "Combobox.Item";
833
+ var Empty = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
834
+ Command.Empty,
835
+ {
836
+ "data-slot": "combobox-empty",
837
+ ref,
838
+ className: cn("px-3 py-6 text-center text-body-sm text-muted-foreground", className),
839
+ ...props
840
+ }
841
+ ));
842
+ Empty.displayName = "Combobox.Empty";
843
+ var Combobox = Object.assign(Root3, { Input: Input2, Content, Item: Item3, Empty });
844
+ var Slider = forwardRef(
845
+ ({
846
+ className,
847
+ defaultValue,
848
+ value,
849
+ min = 0,
850
+ max = 100,
851
+ marks,
852
+ disabled,
853
+ onValueChange,
854
+ "aria-label": ariaLabel,
855
+ "aria-labelledby": ariaLabelledby,
856
+ ...props
857
+ }, ref) => {
858
+ const clamp = (entries) => entries?.map((entry) => Math.min(Math.max(entry, min), max));
859
+ const [internalValue, setInternalValue] = useState(clamp(defaultValue));
860
+ const clampedValue = clamp(value) ?? internalValue;
861
+ const thumbCount = useMemo(() => {
862
+ if (Array.isArray(value)) return value.length;
863
+ if (Array.isArray(defaultValue)) return defaultValue.length;
864
+ return 1;
865
+ }, [value, defaultValue]);
866
+ const span = max - min || 1;
867
+ const visibleMarks = (marks ?? []).filter((mark) => mark.value >= min && mark.value <= max);
868
+ const isRange = thumbCount > 1;
869
+ return /* @__PURE__ */ jsxs("div", { "data-slot": "slider", className: cn("relative w-full", visibleMarks.length > 0 && "pb-5"), children: [
870
+ /* @__PURE__ */ jsxs(
871
+ SliderPrimitive.Root,
872
+ {
873
+ ref,
874
+ "data-slot": "slider-root",
875
+ value: clampedValue,
876
+ min,
877
+ max,
878
+ disabled,
879
+ onValueChange: (next) => {
880
+ if (value === void 0) setInternalValue(next);
881
+ onValueChange?.(next);
882
+ },
883
+ className: cn(
884
+ "relative flex w-full touch-none select-none items-center",
885
+ "data-[disabled]:opacity-50",
886
+ "data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
887
+ className
888
+ ),
889
+ ...props,
890
+ children: [
891
+ /* @__PURE__ */ jsx(
892
+ SliderPrimitive.Track,
893
+ {
894
+ "data-slot": "slider-track",
895
+ className: "relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-1.5",
896
+ children: /* @__PURE__ */ jsx(
897
+ SliderPrimitive.Range,
898
+ {
899
+ "data-slot": "slider-range",
900
+ className: "absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
901
+ }
902
+ )
903
+ }
904
+ ),
905
+ Array.from({ length: thumbCount }, (_, index) => /* @__PURE__ */ jsx(
906
+ SliderPrimitive.Thumb,
907
+ {
908
+ "aria-label": isRange && ariaLabel ? `${ariaLabel} (${index + 1} of ${thumbCount})` : ariaLabel,
909
+ "aria-labelledby": ariaLabelledby,
910
+ "data-slot": "slider-thumb",
911
+ className: "block size-4 shrink-0 rounded-full border border-primary bg-background shadow-sm transition-[box-shadow] hover:ring-4 hover:ring-ring/50 focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50"
912
+ },
913
+ index
914
+ ))
915
+ ]
916
+ }
917
+ ),
918
+ visibleMarks.map((mark) => /* @__PURE__ */ jsx(
919
+ "button",
920
+ {
921
+ type: "button",
922
+ "data-slot": "slider-mark",
923
+ disabled,
924
+ tabIndex: -1,
925
+ "aria-hidden": "true",
926
+ style: { left: `${(mark.value - min) / span * 100}%` },
927
+ className: "-translate-x-1/2 absolute top-4 cursor-pointer text-body-sm text-muted-foreground disabled:cursor-default",
928
+ onClick: () => {
929
+ if (disabled || isRange) return;
930
+ if (value === void 0) setInternalValue([mark.value]);
931
+ onValueChange?.([mark.value]);
932
+ },
933
+ children: mark.label ?? mark.value
934
+ },
935
+ mark.value
936
+ ))
937
+ ] });
938
+ }
939
+ );
940
+ Slider.displayName = "Slider";
289
941
  var UpdateBanner = forwardRef(
290
942
  ({
291
943
  currentVersion,
@@ -361,7 +1013,7 @@ var UpdateBanner = forwardRef(
361
1013
  UpdateBanner.displayName = "UpdateBanner";
362
1014
  var CardContext = createContext({ size: "md" });
363
1015
  var useCardSize = () => useContext(CardContext).size;
364
- var Root2 = forwardRef(
1016
+ var Root5 = forwardRef(
365
1017
  ({ className, size = "md", ...props }, ref) => /* @__PURE__ */ jsx(CardContext.Provider, { value: { size }, children: /* @__PURE__ */ jsx(
366
1018
  "div",
367
1019
  {
@@ -376,7 +1028,7 @@ var Root2 = forwardRef(
376
1028
  }
377
1029
  ) })
378
1030
  );
379
- Root2.displayName = "Card";
1031
+ Root5.displayName = "Card";
380
1032
  var headerPadBySize = {
381
1033
  sm: "gap-1 p-3 pb-1.5",
382
1034
  md: "gap-1.5 p-5 pb-2.5",
@@ -478,49 +1130,13 @@ var Footer = forwardRef(
478
1130
  }
479
1131
  );
480
1132
  Footer.displayName = "Card.Footer";
481
- var Card = /* @__PURE__ */ Object.assign(Root2, {
1133
+ var Card = /* @__PURE__ */ Object.assign(Root5, {
482
1134
  Header,
483
1135
  Title,
484
1136
  Description,
485
1137
  Body,
486
1138
  Footer
487
1139
  });
488
- var inputVariants = cva(
489
- [
490
- "flex w-full rounded-md border border-input bg-card",
491
- "text-foreground placeholder:text-muted-foreground",
492
- "transition-[box-shadow,border-color] duration-base ease-out-soft",
493
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
494
- "focus-visible:border-primary",
495
- "disabled:cursor-not-allowed disabled:opacity-50",
496
- "file:border-0 file:bg-transparent file:font-medium file:text-body-sm"
497
- ],
498
- {
499
- variants: {
500
- size: {
501
- sm: "h-8 px-2.5 py-1 text-body-sm",
502
- // md: density-tunable via CSS var. Comfortable (default) = 36px.
503
- md: "h-[var(--theo-control-h,2.25rem)] px-[var(--theo-control-px,0.875rem)] py-1.5 text-body-sm",
504
- lg: "h-11 px-4 py-2.5 text-body-md"
505
- }
506
- },
507
- defaultVariants: { size: "md" }
508
- }
509
- );
510
- var Input = forwardRef(
511
- ({ className, type = "text", size, ...props }, ref) => /* @__PURE__ */ jsx(
512
- "input",
513
- {
514
- "data-slot": "input",
515
- "data-size": size,
516
- ref,
517
- type,
518
- className: cn(inputVariants({ size }), className),
519
- ...props
520
- }
521
- )
522
- );
523
- Input.displayName = "Input";
524
1140
  var Overlay2 = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
525
1141
  DialogPrimitive.Overlay,
526
1142
  {
@@ -536,7 +1152,7 @@ var Overlay2 = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
536
1152
  }
537
1153
  ));
538
1154
  Overlay2.displayName = "Dialog.Overlay";
539
- var Content2 = forwardRef(
1155
+ var Content3 = forwardRef(
540
1156
  ({ className, children, hideCloseButton, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
541
1157
  /* @__PURE__ */ jsx(Overlay2, {}),
542
1158
  /* @__PURE__ */ jsxs(
@@ -575,7 +1191,7 @@ var Content2 = forwardRef(
575
1191
  )
576
1192
  ] })
577
1193
  );
578
- Content2.displayName = "Dialog.Content";
1194
+ Content3.displayName = "Dialog.Content";
579
1195
  var Header2 = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-1.5 p-6 pb-3 text-left", className), ...props });
580
1196
  Header2.displayName = "Dialog.Header";
581
1197
  var Body2 = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("px-6 pb-6 text-body-md text-muted-foreground", className), ...props });
@@ -613,7 +1229,7 @@ Description3.displayName = "Dialog.Description";
613
1229
  var Dialog = /* @__PURE__ */ Object.assign(DialogPrimitive.Root, {
614
1230
  Trigger: DialogPrimitive.Trigger,
615
1231
  Close: DialogPrimitive.Close,
616
- Content: Content2,
1232
+ Content: Content3,
617
1233
  Overlay: Overlay2,
618
1234
  Header: Header2,
619
1235
  Body: Body2,
@@ -655,7 +1271,7 @@ var Trigger3 = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
655
1271
  }
656
1272
  ));
657
1273
  Trigger3.displayName = "Tabs.Trigger";
658
- var Content4 = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1274
+ var Content5 = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
659
1275
  TabsPrimitive.Content,
660
1276
  {
661
1277
  "data-slot": "tabs-content",
@@ -667,16 +1283,16 @@ var Content4 = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
667
1283
  ...props
668
1284
  }
669
1285
  ));
670
- Content4.displayName = "Tabs.Content";
1286
+ Content5.displayName = "Tabs.Content";
671
1287
  var Tabs = /* @__PURE__ */ Object.assign(TabsPrimitive.Root, {
672
1288
  List: List3,
673
1289
  Trigger: Trigger3,
674
- Content: Content4
1290
+ Content: Content5
675
1291
  });
676
1292
  var Provider2 = TooltipPrimitive.Provider;
677
- var Root6 = TooltipPrimitive.Root;
1293
+ var Root9 = TooltipPrimitive.Root;
678
1294
  var Trigger5 = TooltipPrimitive.Trigger;
679
- var Content6 = forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
1295
+ var Content7 = forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
680
1296
  TooltipPrimitive.Content,
681
1297
  {
682
1298
  "data-slot": "tooltip-content",
@@ -694,7 +1310,7 @@ var Content6 = forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @
694
1310
  ...props
695
1311
  }
696
1312
  ) }));
697
- Content6.displayName = "Tooltip.Content";
1313
+ Content7.displayName = "Tooltip.Content";
698
1314
  var Tooltip = ({
699
1315
  label,
700
1316
  side = "top",
@@ -702,15 +1318,15 @@ var Tooltip = ({
702
1318
  delayDuration = 200,
703
1319
  children,
704
1320
  ...rootProps
705
- }) => /* @__PURE__ */ jsx(Provider2, { delayDuration, children: /* @__PURE__ */ jsxs(Root6, { ...rootProps, children: [
1321
+ }) => /* @__PURE__ */ jsx(Provider2, { delayDuration, children: /* @__PURE__ */ jsxs(Root9, { ...rootProps, children: [
706
1322
  /* @__PURE__ */ jsx(Trigger5, { asChild: true, children }),
707
- /* @__PURE__ */ jsx(Content6, { side, align, children: label })
1323
+ /* @__PURE__ */ jsx(Content7, { side, align, children: label })
708
1324
  ] }) });
709
1325
  var TooltipWithStatics = Tooltip;
710
1326
  TooltipWithStatics.Provider = Provider2;
711
- TooltipWithStatics.Root = Root6;
1327
+ TooltipWithStatics.Root = Root9;
712
1328
  TooltipWithStatics.Trigger = Trigger5;
713
- TooltipWithStatics.Content = Content6;
1329
+ TooltipWithStatics.Content = Content7;
714
1330
  var ScrollAreaRoot = forwardRef(
715
1331
  ({ className, children, orientation = "vertical", size = "thin", type = "hover", ...props }, ref) => /* @__PURE__ */ jsxs(
716
1332
  ScrollAreaPrimitive.Root,
@@ -1560,7 +2176,7 @@ var Textarea = forwardRef(
1560
2176
  )
1561
2177
  );
1562
2178
  Textarea.displayName = "Textarea";
1563
- var Root16 = forwardRef(
2179
+ var Root19 = forwardRef(
1564
2180
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1565
2181
  "aside",
1566
2182
  {
@@ -1574,7 +2190,7 @@ var Root16 = forwardRef(
1574
2190
  }
1575
2191
  )
1576
2192
  );
1577
- Root16.displayName = "Sidebar";
2193
+ Root19.displayName = "Sidebar";
1578
2194
  var Header3 = forwardRef(
1579
2195
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1580
2196
  "div",
@@ -1603,7 +2219,7 @@ var Section = forwardRef(
1603
2219
  )
1604
2220
  );
1605
2221
  Section.displayName = "Sidebar.Section";
1606
- var Item4 = forwardRef(
2222
+ var Item6 = forwardRef(
1607
2223
  ({ className, icon: Icon2, active, count, as = "button", href, children, ...props }, ref) => {
1608
2224
  const classes = cn(
1609
2225
  "group flex w-full items-center gap-3 rounded-lg px-2 py-2",
@@ -1663,7 +2279,7 @@ var Item4 = forwardRef(
1663
2279
  );
1664
2280
  }
1665
2281
  );
1666
- Item4.displayName = "Sidebar.Item";
2282
+ Item6.displayName = "Sidebar.Item";
1667
2283
  var Footer3 = forwardRef(
1668
2284
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1669
2285
  "div",
@@ -1676,13 +2292,13 @@ var Footer3 = forwardRef(
1676
2292
  )
1677
2293
  );
1678
2294
  Footer3.displayName = "Sidebar.Footer";
1679
- var Sidebar = /* @__PURE__ */ Object.assign(Root16, {
2295
+ var Sidebar = /* @__PURE__ */ Object.assign(Root19, {
1680
2296
  Header: Header3,
1681
2297
  Section,
1682
- Item: Item4,
2298
+ Item: Item6,
1683
2299
  Footer: Footer3
1684
2300
  });
1685
- var Root17 = forwardRef(
2301
+ var Root20 = forwardRef(
1686
2302
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1687
2303
  "header",
1688
2304
  {
@@ -1696,7 +2312,7 @@ var Root17 = forwardRef(
1696
2312
  }
1697
2313
  )
1698
2314
  );
1699
- Root17.displayName = "TopNav";
2315
+ Root20.displayName = "TopNav";
1700
2316
  var Left = forwardRef(
1701
2317
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1702
2318
  "div",
@@ -1831,7 +2447,7 @@ var ModeSwitcher = forwardRef(
1831
2447
  }
1832
2448
  );
1833
2449
  ModeSwitcher.displayName = "TopNav.ModeSwitcher";
1834
- var TopNav = /* @__PURE__ */ Object.assign(Root17, {
2450
+ var TopNav = /* @__PURE__ */ Object.assign(Root20, {
1835
2451
  Left,
1836
2452
  Center,
1837
2453
  Right,
@@ -1871,7 +2487,7 @@ var sheetVariants = cva(
1871
2487
  defaultVariants: { side: "right" }
1872
2488
  }
1873
2489
  );
1874
- var Content9 = forwardRef(
2490
+ var Content10 = forwardRef(
1875
2491
  ({ className, children, hideCloseButton, side = "right", ...props }, ref) => /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
1876
2492
  /* @__PURE__ */ jsx(Overlay4, {}),
1877
2493
  /* @__PURE__ */ jsxs(
@@ -1903,7 +2519,7 @@ var Content9 = forwardRef(
1903
2519
  )
1904
2520
  ] })
1905
2521
  );
1906
- Content9.displayName = "Sheet.Content";
2522
+ Content10.displayName = "Sheet.Content";
1907
2523
  var Header4 = ({ className, ...props }) => /* @__PURE__ */ jsx(
1908
2524
  "div",
1909
2525
  {
@@ -1948,7 +2564,7 @@ Description6.displayName = "Sheet.Description";
1948
2564
  var Sheet = DialogPrimitive.Root;
1949
2565
  Sheet.Trigger = DialogPrimitive.Trigger;
1950
2566
  Sheet.Close = DialogPrimitive.Close;
1951
- Sheet.Content = Content9;
2567
+ Sheet.Content = Content10;
1952
2568
  Sheet.Overlay = Overlay4;
1953
2569
  Sheet.Header = Header4;
1954
2570
  Sheet.Body = Body3;
@@ -2127,7 +2743,7 @@ var alignClass = {
2127
2743
  center: "text-center",
2128
2744
  right: "text-right"
2129
2745
  };
2130
- var Root19 = forwardRef(
2746
+ var Root22 = forwardRef(
2131
2747
  ({ className, density = "default", children, ...props }, ref) => /* @__PURE__ */ jsx(TableDensityContext.Provider, { value: density, children: /* @__PURE__ */ jsx(
2132
2748
  "table",
2133
2749
  {
@@ -2139,7 +2755,7 @@ var Root19 = forwardRef(
2139
2755
  }
2140
2756
  ) })
2141
2757
  );
2142
- Root19.displayName = "Table";
2758
+ Root22.displayName = "Table";
2143
2759
  var Header5 = forwardRef(
2144
2760
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2145
2761
  "thead",
@@ -2259,7 +2875,7 @@ var HeaderCell = forwardRef(
2259
2875
  }
2260
2876
  );
2261
2877
  HeaderCell.displayName = "Table.HeaderCell";
2262
- var Table = Object.assign(Root19, { Header: Header5, Body: Body4, Row, Cell, HeaderCell });
2878
+ var Table = Object.assign(Root22, { Header: Header5, Body: Body4, Row, Cell, HeaderCell });
2263
2879
 
2264
2880
  // src/lib/env.ts
2265
2881
  function readNodeEnv() {
@@ -2282,7 +2898,7 @@ var LABEL_COLOR = {
2282
2898
  idle: "text-muted-foreground",
2283
2899
  warning: "text-warning"
2284
2900
  };
2285
- var SIZE = {
2901
+ var SIZE2 = {
2286
2902
  xs: "size-1.5",
2287
2903
  sm: "size-2",
2288
2904
  md: "size-2.5"
@@ -2305,7 +2921,7 @@ var StatusDot = forwardRef(
2305
2921
  "aria-hidden": hasVisibleLabel ? "true" : void 0,
2306
2922
  className: cn(
2307
2923
  "inline-block shrink-0 rounded-full",
2308
- SIZE[size],
2924
+ SIZE2[size],
2309
2925
  DOT_COLOR[status],
2310
2926
  shouldPulse && "animate-pulse"
2311
2927
  )
@@ -2346,102 +2962,6 @@ var StatusDot = forwardRef(
2346
2962
  }
2347
2963
  );
2348
2964
  StatusDot.displayName = "StatusDot";
2349
- var VARIANT = {
2350
- ghost: "hover:bg-muted",
2351
- outline: "border border-border/60 rounded-md"
2352
- };
2353
- var SIZE2 = {
2354
- sm: "px-2 py-1 text-label",
2355
- md: "px-2.5 py-1.5 text-body-sm"
2356
- };
2357
- var CopyButton = forwardRef(
2358
- ({
2359
- className,
2360
- value,
2361
- label,
2362
- variant = "ghost",
2363
- size = "sm",
2364
- onCopied,
2365
- feedbackDuration = 1500,
2366
- ...props
2367
- }, ref) => {
2368
- const [state, setState] = useState("idle");
2369
- const timerRef = useRef(null);
2370
- useEffect(() => {
2371
- return () => {
2372
- if (timerRef.current !== null) {
2373
- clearTimeout(timerRef.current);
2374
- }
2375
- };
2376
- }, []);
2377
- const scheduleRevert = useCallback(() => {
2378
- if (timerRef.current !== null) {
2379
- clearTimeout(timerRef.current);
2380
- }
2381
- timerRef.current = setTimeout(() => {
2382
- setState("idle");
2383
- timerRef.current = null;
2384
- }, feedbackDuration);
2385
- }, [feedbackDuration]);
2386
- const handleClick = useCallback(() => {
2387
- if (state !== "idle") return;
2388
- if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
2389
- setState("failed");
2390
- scheduleRevert();
2391
- return;
2392
- }
2393
- navigator.clipboard.writeText(value).then(
2394
- () => {
2395
- setState("copied");
2396
- onCopied?.(value);
2397
- scheduleRevert();
2398
- },
2399
- () => {
2400
- setState("failed");
2401
- scheduleRevert();
2402
- }
2403
- );
2404
- }, [state, value, onCopied, scheduleRevert]);
2405
- const Icon2 = state === "copied" ? Check : state === "failed" ? X : Copy;
2406
- const liveMessage = state === "copied" ? "Copied to clipboard" : state === "failed" ? "Copy failed" : "";
2407
- const labelText = label !== void 0 ? state === "copied" ? "Copied!" : state === "failed" ? "Failed" : label : null;
2408
- return /* @__PURE__ */ jsxs(
2409
- "button",
2410
- {
2411
- "data-slot": "copy-button",
2412
- ref,
2413
- type: "button",
2414
- onClick: handleClick,
2415
- "data-state": state,
2416
- className: cn(
2417
- "inline-flex items-center gap-1.5",
2418
- "font-sans transition-colors",
2419
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card",
2420
- VARIANT[variant],
2421
- SIZE2[size],
2422
- className
2423
- ),
2424
- ...props,
2425
- children: [
2426
- /* @__PURE__ */ jsx(
2427
- Icon2,
2428
- {
2429
- "aria-hidden": "true",
2430
- className: cn(
2431
- "size-3.5 shrink-0 transition-opacity duration-200",
2432
- state === "copied" && "text-success",
2433
- state === "failed" && "text-destructive"
2434
- )
2435
- }
2436
- ),
2437
- labelText !== null ? /* @__PURE__ */ jsx("span", { children: labelText }) : null,
2438
- /* @__PURE__ */ jsx("span", { className: "sr-only", "aria-live": "polite", children: liveMessage })
2439
- ]
2440
- }
2441
- );
2442
- }
2443
- );
2444
- CopyButton.displayName = "CopyButton";
2445
2965
  function toDate(value) {
2446
2966
  const d = value instanceof Date ? value : new Date(value);
2447
2967
  return Number.isNaN(d.getTime()) ? null : d;
@@ -2636,7 +3156,7 @@ var StatTile = forwardRef(
2636
3156
  }
2637
3157
  );
2638
3158
  StatTile.displayName = "StatTile";
2639
- var Root20 = forwardRef(
3159
+ var Root23 = forwardRef(
2640
3160
  ({ className, title = "Danger Zone", children, ...props }, ref) => /* @__PURE__ */ jsxs(
2641
3161
  "section",
2642
3162
  {
@@ -2652,7 +3172,7 @@ var Root20 = forwardRef(
2652
3172
  }
2653
3173
  )
2654
3174
  );
2655
- Root20.displayName = "DangerZone";
3175
+ Root23.displayName = "DangerZone";
2656
3176
  var Action2 = forwardRef(
2657
3177
  ({ className, title, description, action, ...props }, ref) => /* @__PURE__ */ jsxs(
2658
3178
  "div",
@@ -2675,7 +3195,7 @@ var Action2 = forwardRef(
2675
3195
  )
2676
3196
  );
2677
3197
  Action2.displayName = "DangerZone.Action";
2678
- var DangerZone = Object.assign(Root20, { Action: Action2 });
3198
+ var DangerZone = Object.assign(Root23, { Action: Action2 });
2679
3199
  var ConfirmDialog = forwardRef(
2680
3200
  ({
2681
3201
  open,
@@ -3187,7 +3707,7 @@ var Portal6 = DropdownMenuPrimitive.Portal;
3187
3707
  var Group3 = DropdownMenuPrimitive.Group;
3188
3708
  var Sub2 = DropdownMenuPrimitive.Sub;
3189
3709
  var RadioGroup3 = DropdownMenuPrimitive.RadioGroup;
3190
- var Content11 = forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
3710
+ var Content12 = forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
3191
3711
  DropdownMenuPrimitive.Content,
3192
3712
  {
3193
3713
  "data-slot": "dropdown-menu-content",
@@ -3203,8 +3723,8 @@ var Content11 = forwardRef(({ className, sideOffset = 4, ...props }, ref) => /*
3203
3723
  ...props
3204
3724
  }
3205
3725
  ) }));
3206
- Content11.displayName = "DropdownMenu.Content";
3207
- var Item6 = forwardRef(
3726
+ Content12.displayName = "DropdownMenu.Content";
3727
+ var Item8 = forwardRef(
3208
3728
  ({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
3209
3729
  DropdownMenuPrimitive.Item,
3210
3730
  {
@@ -3223,7 +3743,7 @@ var Item6 = forwardRef(
3223
3743
  }
3224
3744
  )
3225
3745
  );
3226
- Item6.displayName = "DropdownMenu.Item";
3746
+ Item8.displayName = "DropdownMenu.Item";
3227
3747
  var CheckboxItem2 = forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(
3228
3748
  DropdownMenuPrimitive.CheckboxItem,
3229
3749
  {
@@ -3338,8 +3858,8 @@ SubContent2.displayName = "DropdownMenu.SubContent";
3338
3858
  var DropdownMenu = Object.assign(DropdownMenuPrimitive.Root, {
3339
3859
  Trigger: Trigger9,
3340
3860
  Portal: Portal6,
3341
- Content: Content11,
3342
- Item: Item6,
3861
+ Content: Content12,
3862
+ Item: Item8,
3343
3863
  CheckboxItem: CheckboxItem2,
3344
3864
  RadioItem: RadioItem2,
3345
3865
  Label: Label4,
@@ -4788,4 +5308,4 @@ function CommandPalette({
4788
5308
  ] }) });
4789
5309
  }
4790
5310
 
4791
- export { AccountMenu, ActionBar, Alert, Avatar, BadgeWithDot as Badge, Breadcrumb, Button, Card, Checkbox, CodeBlock, CommandPalette, ConfirmDialog, CopyButton, DangerZone, DataTable, DeploymentRow, Dialog, DomainConfig, DropdownMenu, EmptyState, EnvVarEditor, FormField, Input, Label, LoginSplit, MetricCard, MetricsPanel, PageShell, Pagination, PinInput, PlanBadge, PreviewEnvCard, Progress, ProjectCard, RadioGroup, RollbackUI, ScrollArea, Select, Sheet, Sidebar, Skeleton, SocialAuthRow, StatTile, StatusDot, StatusIndicator, Switch, Table, Tabs, TaskHeader, Textarea, Timestamp, Toast, Toaster, TooltipWithStatics as Tooltip, TopNav, UpdateBanner, avatarVariants, badgeVariants, buttonVariants, cn, computePageRange, isNearBottom, sheetVariants, useStickToBottom, useToast };
5311
+ export { AccountMenu, ActionBar, Alert, Avatar, BadgeWithDot as Badge, Breadcrumb, Button, Card, Checkbox, CodeBlock, Combobox, CommandPalette, ConfirmDialog, CopyButton, DangerZone, DataTable, DeploymentRow, DescriptionList, Dialog, DomainConfig, DropdownMenu, EmptyState, EnvVarEditor, FormField, Input, JsonViewer, Label, LoginSplit, MetricCard, MetricsPanel, PageShell, Pagination, PinInput, PlanBadge, PreviewEnvCard, Progress, ProjectCard, RadioGroup, RollbackUI, ScrollArea, Select, Sheet, Sidebar, Skeleton, Slider, SocialAuthRow, StatTile, StatusDot, StatusIndicator, Switch, Table, Tabs, TaskHeader, Textarea, Timestamp, Toast, Toaster, TooltipWithStatics as Tooltip, TopNav, UpdateBanner, avatarVariants, badgeVariants, buttonVariants, cn, computePageRange, isNearBottom, sheetVariants, useStickToBottom, useToast };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usetheo/ui",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Violet Forge design system — generic React components + primitives (the non-AI foundation of @theokit/ui).",
@@ -34,6 +34,7 @@
34
34
  "@radix-ui/react-radio-group": "^1.3.8",
35
35
  "@radix-ui/react-scroll-area": "^1.2.10",
36
36
  "@radix-ui/react-select": "^2.2.6",
37
+ "@radix-ui/react-slider": "^1.4.3",
37
38
  "@radix-ui/react-slot": "^1.1.2",
38
39
  "@radix-ui/react-switch": "^1.2.6",
39
40
  "@radix-ui/react-tabs": "^1.1.3",