@corbits/react-ui 0.1.0 → 0.2.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.
Files changed (170) hide show
  1. package/LICENSE +174 -499
  2. package/README.md +228 -85
  3. package/dist/blocks/login/auth-layout.d.ts +1 -1
  4. package/dist/blocks/login/auth-layout.js +3 -33
  5. package/dist/blocks/login/login-form.js +6 -119
  6. package/dist/hooks/use-command-palette-navigation.js +18 -17
  7. package/dist/hooks/use-controllable-state.d.ts +2 -2
  8. package/dist/hooks/use-controllable-state.js +23 -15
  9. package/dist/hooks/use-delayed-autofocus.js +10 -11
  10. package/dist/hooks/use-dismissable-popover.d.ts +2 -2
  11. package/dist/hooks/use-dismissable-popover.js +21 -29
  12. package/dist/hooks/use-list-selection.js +54 -85
  13. package/dist/hooks/use-prefers-reduced-motion.js +8 -4
  14. package/dist/hooks/use-scroll-current-into-view.js +5 -7
  15. package/dist/index.d.ts +0 -11
  16. package/dist/index.js +10 -19
  17. package/dist/lib/artifact.js +16 -35
  18. package/dist/lib/chart-geometry.js +33 -20
  19. package/dist/lib/chart-palette.js +17 -31
  20. package/dist/lib/chat-message.js +32 -13
  21. package/dist/lib/chat-parts.js +2 -1
  22. package/dist/lib/csv.js +42 -26
  23. package/dist/lib/metrics.js +30 -48
  24. package/dist/lib/now-item.js +26 -25
  25. package/dist/lib/relative-time.js +14 -29
  26. package/dist/lib/theme.js +32 -30
  27. package/dist/lib/url.js +9 -8
  28. package/dist/lib/workflow-display-flow.js +37 -33
  29. package/dist/lib/workflow-registry.d.ts +0 -41
  30. package/dist/lib/workflow-registry.js +13 -23
  31. package/dist/lib/workflow-run-error.js +16 -20
  32. package/dist/lib/workflow-run-progress.js +94 -52
  33. package/dist/lib/workflow-run.js +17 -13
  34. package/dist/styles.css +11 -11
  35. package/dist/test/render-hook.js +11 -12
  36. package/dist/theme.css +51 -14
  37. package/dist/ui/agent-turn.d.ts +1 -1
  38. package/dist/ui/agent-turn.js +4 -37
  39. package/dist/ui/animated-number.js +15 -28
  40. package/dist/ui/approval-card.js +5 -90
  41. package/dist/ui/artifact-body.js +47 -125
  42. package/dist/ui/artifact-notice.d.ts +1 -1
  43. package/dist/ui/artifact-notice.js +9 -16
  44. package/dist/ui/avatar.d.ts +1 -1
  45. package/dist/ui/avatar.js +11 -48
  46. package/dist/ui/badge.js +4 -12
  47. package/dist/ui/bar-chart.d.ts +1 -1
  48. package/dist/ui/bar-chart.js +22 -74
  49. package/dist/ui/block-card.js +7 -45
  50. package/dist/ui/boot-screen.d.ts +1 -1
  51. package/dist/ui/boot-screen.js +4 -33
  52. package/dist/ui/bulk-action-bar.d.ts +1 -1
  53. package/dist/ui/bulk-action-bar.js +14 -33
  54. package/dist/ui/button.js +10 -24
  55. package/dist/ui/card.js +5 -25
  56. package/dist/ui/category-bars.js +14 -59
  57. package/dist/ui/chart-frame.d.ts +2 -2
  58. package/dist/ui/chart-frame.js +6 -85
  59. package/dist/ui/chat-composer.js +4 -16
  60. package/dist/ui/chat-dock-timing.js +7 -3
  61. package/dist/ui/chat-input.js +20 -100
  62. package/dist/ui/chat-panel.d.ts +1 -1
  63. package/dist/ui/chat-panel.js +7 -41
  64. package/dist/ui/chat-thread.js +13 -31
  65. package/dist/ui/checkbox.js +10 -52
  66. package/dist/ui/command-palette.js +71 -246
  67. package/dist/ui/compare-body.d.ts +1 -1
  68. package/dist/ui/compare-body.js +28 -98
  69. package/dist/ui/confirm-button.js +8 -15
  70. package/dist/ui/corbits-mark.js +7 -16
  71. package/dist/ui/csv-table.d.ts +1 -1
  72. package/dist/ui/csv-table.js +8 -50
  73. package/dist/ui/dialog.d.ts +1 -1
  74. package/dist/ui/dialog.js +32 -62
  75. package/dist/ui/dictation-status-line.js +7 -25
  76. package/dist/ui/dither-canvas.d.ts +1 -1
  77. package/dist/ui/dither-canvas.js +31 -56
  78. package/dist/ui/embed-body.d.ts +1 -1
  79. package/dist/ui/embed-body.js +7 -56
  80. package/dist/ui/empty-state.d.ts +1 -1
  81. package/dist/ui/empty-state.js +3 -26
  82. package/dist/ui/file-input.js +17 -37
  83. package/dist/ui/filter-bar.d.ts +1 -1
  84. package/dist/ui/filter-bar.js +11 -71
  85. package/dist/ui/filter-chip.d.ts +1 -1
  86. package/dist/ui/filter-chip.js +7 -15
  87. package/dist/ui/gate-block.d.ts +2 -1
  88. package/dist/ui/gate-block.js +4 -29
  89. package/dist/ui/horizontal-stepper.d.ts +1 -1
  90. package/dist/ui/horizontal-stepper.js +18 -45
  91. package/dist/ui/input.js +1 -6
  92. package/dist/ui/inspector-shell.d.ts +5 -5
  93. package/dist/ui/inspector-shell.js +14 -81
  94. package/dist/ui/intake-form.d.ts +1 -1
  95. package/dist/ui/intake-form.js +21 -97
  96. package/dist/ui/kind-card-grid.js +9 -31
  97. package/dist/ui/library-page-header.js +4 -32
  98. package/dist/ui/list-detail.js +5 -35
  99. package/dist/ui/live-run-banner.d.ts +1 -1
  100. package/dist/ui/live-run-banner.js +5 -15
  101. package/dist/ui/live-status-line.js +6 -24
  102. package/dist/ui/menu.js +7 -24
  103. package/dist/ui/message-bubble.d.ts +3 -3
  104. package/dist/ui/message-bubble.js +5 -44
  105. package/dist/ui/mic-button.d.ts +1 -1
  106. package/dist/ui/mic-button.js +15 -21
  107. package/dist/ui/mic-permission-dialog.js +5 -41
  108. package/dist/ui/notifications-bell.js +9 -43
  109. package/dist/ui/now-cards.d.ts +2 -2
  110. package/dist/ui/now-cards.js +16 -94
  111. package/dist/ui/page-panel.js +11 -11
  112. package/dist/ui/page-shell.js +4 -11
  113. package/dist/ui/parts-renderer.js +51 -149
  114. package/dist/ui/profile-card.js +7 -111
  115. package/dist/ui/progress-checklist.js +11 -49
  116. package/dist/ui/provider-mark.d.ts +2 -2
  117. package/dist/ui/provider-mark.js +9 -16
  118. package/dist/ui/quick-reply-chips.js +6 -14
  119. package/dist/ui/quote-card.js +12 -32
  120. package/dist/ui/reasoning-block.d.ts +1 -1
  121. package/dist/ui/reasoning-block.js +14 -33
  122. package/dist/ui/research-body.js +32 -213
  123. package/dist/ui/rich-empty-state.js +6 -48
  124. package/dist/ui/run-now-button.js +14 -15
  125. package/dist/ui/section.d.ts +1 -1
  126. package/dist/ui/section.js +4 -40
  127. package/dist/ui/select.js +1 -15
  128. package/dist/ui/selection-checkbox.d.ts +1 -1
  129. package/dist/ui/selection-checkbox.js +11 -29
  130. package/dist/ui/settings-panel.js +7 -50
  131. package/dist/ui/shimmer-text.js +3 -6
  132. package/dist/ui/sidebar-item-row.d.ts +1 -1
  133. package/dist/ui/sidebar-item-row.js +9 -39
  134. package/dist/ui/sidebar-panel.js +15 -40
  135. package/dist/ui/sidebar.js +15 -76
  136. package/dist/ui/skeleton.js +3 -7
  137. package/dist/ui/sortable-table.js +29 -72
  138. package/dist/ui/sparkline.js +14 -38
  139. package/dist/ui/stat-grid.js +17 -52
  140. package/dist/ui/status-dot.d.ts +1 -1
  141. package/dist/ui/status-dot.js +8 -20
  142. package/dist/ui/step-list.d.ts +1 -0
  143. package/dist/ui/step-list.js +11 -50
  144. package/dist/ui/switch.js +4 -16
  145. package/dist/ui/table.js +7 -32
  146. package/dist/ui/tabs.js +39 -54
  147. package/dist/ui/textarea.js +10 -19
  148. package/dist/ui/theme-provider.js +54 -78
  149. package/dist/ui/theme-toggle.js +13 -16
  150. package/dist/ui/thinking-indicator.js +3 -15
  151. package/dist/ui/thinking-label.js +16 -35
  152. package/dist/ui/thinking-mark.d.ts +1 -1
  153. package/dist/ui/thinking-mark.js +4 -145
  154. package/dist/ui/time-series-chart.js +43 -174
  155. package/dist/ui/toast.js +12 -20
  156. package/dist/ui/token-mosaic.js +5 -43
  157. package/dist/ui/tool-block.js +18 -70
  158. package/dist/ui/tool-narrative.d.ts +1 -1
  159. package/dist/ui/tool-narrative.js +10 -57
  160. package/dist/ui/tool-picker.js +57 -145
  161. package/dist/ui/tooltip.d.ts +1 -1
  162. package/dist/ui/tooltip.js +4 -33
  163. package/dist/ui/top-bar.js +14 -72
  164. package/dist/ui/trace-waterfall.d.ts +1 -1
  165. package/dist/ui/trace-waterfall.js +21 -93
  166. package/dist/ui/typing-indicator.d.ts +1 -1
  167. package/dist/ui/typing-indicator.js +4 -18
  168. package/dist/ui/view-toggle.js +10 -29
  169. package/dist/ui/voice-waveform.js +3 -11
  170. package/package.json +94 -535
@@ -8,59 +8,21 @@ import { cn } from "../lib/utils.js";
8
8
  * can tell "the agent made this" at a glance. Lifted out of a consumer app
9
9
  * unchanged; see `RiskBadge` below for the tone it pairs with inside
10
10
  * `children`.
11
- */ export function BlockCard({ title, children, className }) {
12
- return /*#__PURE__*/ _jsxs("div", {
13
- "data-slot": "block-card",
14
- className: cn("overflow-hidden rounded-none border border-border bg-card", className),
15
- children: [
16
- /*#__PURE__*/ _jsxs("div", {
17
- "data-slot": "block-card-header",
18
- className: "flex items-center gap-2 border-b border-border px-3.5 py-2.5 text-xs font-bold tracking-[0.02em] text-primary-emphasis",
19
- children: [
20
- /*#__PURE__*/ _jsx("span", {
21
- "aria-hidden": true,
22
- className: "size-1.5 shrink-0 rounded-none bg-current [animation:corbits-block-pulse_1.6s_ease_infinite]"
23
- }),
24
- /*#__PURE__*/ _jsx("span", {
25
- "data-slot": "block-card-title",
26
- children: title
27
- })
28
- ]
29
- }),
30
- /*#__PURE__*/ _jsx("div", {
31
- "data-slot": "block-card-body",
32
- className: "p-4",
33
- children: children
34
- })
35
- ]
36
- });
11
+ */
12
+ export function BlockCard({ title, children, className }) {
13
+ return (_jsxs("div", { "data-slot": "block-card", className: cn("overflow-hidden rounded-none border border-border bg-card", className), children: [_jsxs("div", { "data-slot": "block-card-header", className: "flex items-center gap-2 border-b border-border px-3.5 py-2.5 text-xs font-bold tracking-[0.02em] text-primary-emphasis", children: [_jsx("span", { "aria-hidden": true, className: "size-1.5 shrink-0 rounded-none bg-current [animation:corbits-block-pulse_1.6s_ease_infinite]" }), _jsx("span", { "data-slot": "block-card-title", children: title })] }), _jsx("div", { "data-slot": "block-card-body", className: "p-4", children: children })] }));
37
14
  }
38
15
  const RISK_TONE_CLASS = {
39
16
  low: "text-muted-foreground",
40
17
  medium: "text-warn",
41
- high: "text-destructive"
18
+ high: "text-destructive",
42
19
  };
43
20
  /**
44
21
  * A risk callout for a block whose action carries consequence — approve this
45
22
  * order cancellation, run this migration. `level` drives colour only; the
46
23
  * `label` is what actually says what the risk is, so the badge is never a
47
24
  * bare colour dot.
48
- */ export function RiskBadge({ level, label, note, className }) {
49
- return /*#__PURE__*/ _jsxs("span", {
50
- "data-slot": "risk-badge",
51
- "data-risk": level,
52
- className: cn("inline-flex items-center gap-1.5 text-xs font-bold [&_svg]:size-3.5", RISK_TONE_CLASS[level], className),
53
- children: [
54
- /*#__PURE__*/ _jsx(TriangleAlert, {
55
- "aria-hidden": true
56
- }),
57
- /*#__PURE__*/ _jsx("span", {
58
- children: label
59
- }),
60
- note === undefined ? null : /*#__PURE__*/ _jsx("span", {
61
- className: "font-medium text-muted-foreground",
62
- children: note
63
- })
64
- ]
65
- });
25
+ */
26
+ export function RiskBadge({ level, label, note, className }) {
27
+ return (_jsxs("span", { "data-slot": "risk-badge", "data-risk": level, className: cn("inline-flex items-center gap-1.5 text-xs font-bold [&_svg]:size-3.5", RISK_TONE_CLASS[level], className), children: [_jsx(TriangleAlert, { "aria-hidden": true }), _jsx("span", { children: label }), note === undefined ? null : (_jsx("span", { className: "font-medium text-muted-foreground", children: note }))] }));
66
28
  }
@@ -20,4 +20,4 @@ export type BootScreenProps = {
20
20
  * to a still frame under the theme's reduced-motion rule with nothing to do
21
21
  * here.
22
22
  */
23
- export declare function BootScreen({ message, brand, footer, className }: BootScreenProps): import("react").JSX.Element;
23
+ export declare function BootScreen({ message, brand, footer, className, }: BootScreenProps): import("react").JSX.Element;
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useId } from "react";
3
4
  import { cn } from "../lib/utils.js";
@@ -12,38 +13,8 @@ import { cn } from "../lib/utils.js";
12
13
  * No spinner: the pulsing bar is decorative and `aria-hidden`, and it collapses
13
14
  * to a still frame under the theme's reduced-motion rule with nothing to do
14
15
  * here.
15
- */ export function BootScreen({ message, brand, footer, className }) {
16
+ */
17
+ export function BootScreen({ message, brand, footer, className, }) {
16
18
  const messageId = useId();
17
- return /*#__PURE__*/ _jsxs("div", {
18
- role: "status",
19
- "aria-labelledby": messageId,
20
- className: cn("absolute inset-0 overflow-hidden bg-background text-foreground", className),
21
- children: [
22
- brand === undefined ? null : /*#__PURE__*/ _jsx("div", {
23
- className: "absolute top-6 left-7",
24
- children: brand
25
- }),
26
- /*#__PURE__*/ _jsxs("div", {
27
- className: "absolute inset-0 flex flex-col items-center justify-center gap-4 p-6",
28
- children: [
29
- /*#__PURE__*/ _jsx("span", {
30
- "aria-hidden": true,
31
- className: "h-0.5 w-24 overflow-hidden rounded-full bg-muted",
32
- children: /*#__PURE__*/ _jsx("span", {
33
- className: "block h-full w-1/3 rounded-full bg-primary [animation:corbits-boot-sweep_1.4s_ease-in-out_infinite]"
34
- })
35
- }),
36
- /*#__PURE__*/ _jsx("p", {
37
- id: messageId,
38
- className: "max-w-[32ch] text-center text-xs leading-relaxed text-muted-foreground",
39
- children: message
40
- })
41
- ]
42
- }),
43
- footer === undefined ? null : /*#__PURE__*/ _jsx("div", {
44
- className: "absolute bottom-6 left-7 font-mono text-[11px] text-muted-foreground",
45
- children: footer
46
- })
47
- ]
48
- });
19
+ return (_jsxs("div", { role: "status", "aria-labelledby": messageId, className: cn("absolute inset-0 overflow-hidden bg-background text-foreground", className), children: [brand === undefined ? null : (_jsx("div", { className: "absolute top-6 left-7", children: brand })), _jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-4 p-6", children: [_jsx("span", { "aria-hidden": true, className: "h-0.5 w-24 overflow-hidden rounded-full bg-muted", children: _jsx("span", { className: "block h-full w-1/3 rounded-full bg-primary [animation:corbits-boot-sweep_1.4s_ease-in-out_infinite]" }) }), _jsx("p", { id: messageId, className: "max-w-[32ch] text-center text-xs leading-relaxed text-muted-foreground", children: message })] }), footer === undefined ? null : (_jsx("div", { className: "absolute bottom-6 left-7 font-mono text-[11px] text-muted-foreground", children: footer }))] }));
49
20
  }
@@ -34,4 +34,4 @@ export type BulkActionBarProps = {
34
34
  * already handled its own Escape wins instead of also clearing the
35
35
  * selection underneath it.
36
36
  */
37
- export declare function BulkActionBar({ count, onClear, children, label, className }: BulkActionBarProps): import("react").JSX.Element | null;
37
+ export declare function BulkActionBar({ count, onClear, children, label, className, }: BulkActionBarProps): import("react").JSX.Element | null;
@@ -1,4 +1,5 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ "use client";
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
3
  import { useEffect } from "react";
3
4
  import { cn } from "../lib/utils.js";
4
5
  /**
@@ -26,39 +27,19 @@ import { cn } from "../lib/utils.js";
26
27
  * `event.defaultPrevented`, so a dialog or input stacked above the bar that
27
28
  * already handled its own Escape wins instead of also clearing the
28
29
  * selection underneath it.
29
- */ export function BulkActionBar({ count, onClear, children, label = "Bulk actions", className }) {
30
- useEffect(()=>{
31
- if (count === 0) return;
30
+ */
31
+ export function BulkActionBar({ count, onClear, children, label = "Bulk actions", className, }) {
32
+ useEffect(() => {
33
+ if (count === 0)
34
+ return;
32
35
  function onKeyDown(event) {
33
- if (event.key === "Escape" && !event.defaultPrevented) onClear();
36
+ if (event.key === "Escape" && !event.defaultPrevented)
37
+ onClear();
34
38
  }
35
39
  window.addEventListener("keydown", onKeyDown);
36
- return ()=>window.removeEventListener("keydown", onKeyDown);
37
- }, [
38
- count,
39
- onClear
40
- ]);
41
- if (count === 0) return null;
42
- return /*#__PURE__*/ _jsx("div", {
43
- className: cn("fixed bottom-6 left-1/2 z-40 -translate-x-1/2", className),
44
- children: /*#__PURE__*/ _jsxs("div", {
45
- role: "group",
46
- "aria-label": label,
47
- className: cn("flex items-center gap-3 rounded-full border border-border bg-card px-4 py-2 shadow-lg", "motion-safe:[animation:corbits-bulk-action-bar-in_220ms_var(--ease-out)_both]"),
48
- children: [
49
- /*#__PURE__*/ _jsxs("span", {
50
- "aria-live": "polite",
51
- className: "text-sm font-medium whitespace-nowrap",
52
- children: [
53
- count,
54
- " selected"
55
- ]
56
- }),
57
- /*#__PURE__*/ _jsx("div", {
58
- className: "flex items-center gap-2",
59
- children: children
60
- })
61
- ]
62
- })
63
- });
40
+ return () => window.removeEventListener("keydown", onKeyDown);
41
+ }, [count, onClear]);
42
+ if (count === 0)
43
+ return null;
44
+ return (_jsx("div", { className: cn("fixed bottom-6 left-1/2 z-40 -translate-x-1/2", className), children: _jsxs("div", { role: "group", "aria-label": label, className: cn("flex items-center gap-3 rounded-full border border-border bg-card px-4 py-2 shadow-lg", "motion-safe:[animation:corbits-bulk-action-bar-in_220ms_var(--ease-out)_both]"), children: [_jsxs("span", { "aria-live": "polite", className: "text-sm font-medium whitespace-nowrap", children: [count, " selected"] }), _jsx("div", { className: "flex items-center gap-2", children: children })] }) }));
64
45
  }
package/dist/ui/button.js CHANGED
@@ -10,7 +10,8 @@ import { cn } from "../lib/utils.js";
10
10
  // orange primary. That measures 2.69:1, a hard AA failure. `text-primary-
11
11
  // foreground` resolves to ink in light (5.53:1) and black in dark (5.34:1),
12
12
  // which is correct. DESIGN.md is wrong; do not "fix" this back.
13
- const buttonVariantsBase = cva(// active:brightness-95 is the press state for every variant: it darkens the
13
+ const buttonVariantsBase = cva(
14
+ // active:brightness-95 is the press state for every variant: it darkens the
14
15
  // rendered fill whatever that fill is, so it needs no per-variant pressed
15
16
  // token. Deliberately outside `transition-colors` — a press should land on
16
17
  // the frame the pointer goes down, not ease in. The scale feedback gets its
@@ -24,33 +25,25 @@ const buttonVariantsBase = cva(// active:brightness-95 is the press state for ev
24
25
  outline: "border border-input bg-transparent hover:bg-muted",
25
26
  ghost: "hover:bg-muted",
26
27
  link: "text-primary-emphasis underline-offset-4 hover:underline",
27
- destructive: "bg-destructive text-destructive-foreground hover:opacity-90"
28
+ destructive: "bg-destructive text-destructive-foreground hover:opacity-90",
28
29
  },
29
30
  size: {
30
31
  sm: "h-8 px-3",
31
32
  md: "h-9 px-4",
32
33
  lg: "h-10 px-6",
33
- icon: "size-9"
34
- }
34
+ icon: "size-9",
35
+ },
35
36
  },
36
37
  // link reads as inline text, not a control — it opts out of every size's
37
38
  // fixed height/padding rather than getting a box of its own.
38
39
  compoundVariants: [
39
40
  {
40
41
  variant: "link",
41
- size: [
42
- "sm",
43
- "md",
44
- "lg",
45
- "icon"
46
- ],
47
- class: "h-auto px-0"
48
- }
42
+ size: ["sm", "md", "lg", "icon"],
43
+ class: "h-auto px-0",
44
+ },
49
45
  ],
50
- defaultVariants: {
51
- variant: "primary",
52
- size: "md"
53
- }
46
+ defaultVariants: { variant: "primary", size: "md" },
54
47
  });
55
48
  // cva concatenates variant, size, and compound-variant classes as plain
56
49
  // strings with no dedup, so the compound override above only wins once
@@ -61,13 +54,6 @@ function buttonVariants(props) {
61
54
  }
62
55
  export function Button({ className, variant, size, asChild = false, ...props }) {
63
56
  const Comp = asChild ? Slot : "button";
64
- return /*#__PURE__*/ _jsx(Comp, {
65
- "data-slot": "button",
66
- className: cn(buttonVariants({
67
- variant,
68
- size
69
- }), className),
70
- ...props
71
- });
57
+ return (_jsx(Comp, { "data-slot": "button", className: cn(buttonVariants({ variant, size }), className), ...props }));
72
58
  }
73
59
  export { buttonVariants };
package/dist/ui/card.js CHANGED
@@ -1,37 +1,17 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/utils.js";
3
3
  export function Card({ className, ...props }) {
4
- return /*#__PURE__*/ _jsx("div", {
5
- "data-slot": "card",
6
- className: cn("flex flex-col gap-4 rounded-lg border border-border bg-card p-6 text-card-foreground", className),
7
- ...props
8
- });
4
+ return (_jsx("div", { "data-slot": "card", className: cn("flex flex-col gap-4 rounded-lg border border-border bg-card p-6 text-card-foreground", className), ...props }));
9
5
  }
10
6
  export function CardHeader({ className, ...props }) {
11
- return /*#__PURE__*/ _jsx("div", {
12
- "data-slot": "card-header",
13
- className: cn("flex flex-col gap-1", className),
14
- ...props
15
- });
7
+ return (_jsx("div", { "data-slot": "card-header", className: cn("flex flex-col gap-1", className), ...props }));
16
8
  }
17
9
  export function CardTitle({ className, ...props }) {
18
- return /*#__PURE__*/ _jsx("h3", {
19
- "data-slot": "card-title",
20
- className: cn("text-base leading-none font-semibold", className),
21
- ...props
22
- });
10
+ return (_jsx("h3", { "data-slot": "card-title", className: cn("text-base leading-none font-semibold", className), ...props }));
23
11
  }
24
12
  export function CardDescription({ className, ...props }) {
25
- return /*#__PURE__*/ _jsx("p", {
26
- "data-slot": "card-description",
27
- className: cn("text-sm text-muted-foreground", className),
28
- ...props
29
- });
13
+ return (_jsx("p", { "data-slot": "card-description", className: cn("text-sm text-muted-foreground", className), ...props }));
30
14
  }
31
15
  export function CardFooter({ className, ...props }) {
32
- return /*#__PURE__*/ _jsx("div", {
33
- "data-slot": "card-footer",
34
- className: cn("flex items-center gap-2", className),
35
- ...props
36
- });
16
+ return (_jsx("div", { "data-slot": "card-footer", className: cn("flex items-center gap-2", className), ...props }));
37
17
  }
@@ -6,64 +6,19 @@ import { ChartFrame } from "./chart-frame.js";
6
6
  * Dense horizontal category ranking for cost-by-model / calls-by-tool
7
7
  * style tables. Bars share one series colour; length encodes magnitude.
8
8
  * Absent secondary labels stay empty rather than inventing a zero.
9
- */ export function CategoryBars({ title, description, data, valueLabel = "Value", format = formatCompact, className }) {
10
- const max = Math.max(0, ...data.map((d)=>d.value));
9
+ */
10
+ export function CategoryBars({ title, description, data, valueLabel = "Value", format = formatCompact, className, }) {
11
+ const max = Math.max(0, ...data.map((d) => d.value));
11
12
  const axisMax = max === 0 ? 1 : max;
12
- return /*#__PURE__*/ _jsx(ChartFrame, {
13
- title: title,
14
- ...description === undefined ? {} : {
15
- description
16
- },
17
- table: {
18
- columns: [
19
- "Category",
20
- valueLabel,
21
- "Detail"
22
- ],
23
- rows: data.map((datum)=>[
24
- datum.label,
25
- format(datum.value),
26
- datum.secondaryLabel ?? "—"
27
- ])
28
- },
29
- className: className,
30
- children: /*#__PURE__*/ _jsx("div", {
31
- className: "flex flex-col gap-2",
32
- role: "presentation",
33
- children: data.map((datum)=>{
34
- const pct = datum.value / axisMax * 100;
35
- return /*#__PURE__*/ _jsxs("div", {
36
- className: "grid grid-cols-[minmax(6rem,10rem)_1fr_auto] items-center gap-2",
37
- children: [
38
- /*#__PURE__*/ _jsx("p", {
39
- className: "truncate text-xs font-medium",
40
- children: datum.label
41
- }),
42
- /*#__PURE__*/ _jsx("div", {
43
- className: "h-3 w-full bg-muted",
44
- children: /*#__PURE__*/ _jsx("div", {
45
- className: cn("h-full bg-primary-emphasis"),
46
- style: {
47
- width: `${pct}%`
48
- }
49
- })
50
- }),
51
- /*#__PURE__*/ _jsxs("div", {
52
- className: "min-w-[3.5rem] text-right font-mono text-[11px] leading-tight",
53
- children: [
54
- /*#__PURE__*/ _jsx("p", {
55
- className: "font-semibold",
56
- children: format(datum.value)
57
- }),
58
- datum.secondaryLabel === undefined ? null : /*#__PURE__*/ _jsx("p", {
59
- className: "text-muted-foreground",
60
- children: datum.secondaryLabel
61
- })
62
- ]
63
- })
64
- ]
65
- }, datum.label);
66
- })
67
- })
68
- });
13
+ return (_jsx(ChartFrame, { title: title, ...(description === undefined ? {} : { description }), table: {
14
+ columns: ["Category", valueLabel, "Detail"],
15
+ rows: data.map((datum) => [
16
+ datum.label,
17
+ format(datum.value),
18
+ datum.secondaryLabel ?? "—",
19
+ ]),
20
+ }, className: className, children: _jsx("div", { className: "flex flex-col gap-2", role: "presentation", children: data.map((datum) => {
21
+ const pct = (datum.value / axisMax) * 100;
22
+ return (_jsxs("div", { className: "grid grid-cols-[minmax(6rem,10rem)_1fr_auto] items-center gap-2", children: [_jsx("p", { className: "truncate text-xs font-medium", children: datum.label }), _jsx("div", { className: "h-3 w-full bg-muted", children: _jsx("div", { className: cn("h-full bg-primary-emphasis"), style: { width: `${pct}%` } }) }), _jsxs("div", { className: "min-w-[3.5rem] text-right font-mono text-[11px] leading-tight", children: [_jsx("p", { className: "font-semibold", children: format(datum.value) }), datum.secondaryLabel === undefined ? null : (_jsx("p", { className: "text-muted-foreground", children: datum.secondaryLabel }))] })] }, datum.label));
23
+ }) }) }));
69
24
  }
@@ -29,7 +29,7 @@ export type ChartFrameProps = {
29
29
  readonly table: ChartTable;
30
30
  /** The plot itself — an `<svg>`. */
31
31
  readonly children: ReactNode;
32
- readonly className?: string;
32
+ readonly className?: string | undefined;
33
33
  };
34
34
  /**
35
35
  * The frame every chart here sits in: a caption, a legend, the plot, and the
@@ -51,4 +51,4 @@ export type ChartFrameProps = {
51
51
  * cross-reference. Text never wears the series colour: a mid-lightness hue that
52
52
  * is correct for a 24px bar is unreadable at 12px.
53
53
  */
54
- export declare function ChartFrame({ title, description, legend, table, children, className }: ChartFrameProps): import("react").JSX.Element;
54
+ export declare function ChartFrame({ title, description, legend, table, children, className, }: ChartFrameProps): import("react").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/utils.js";
3
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./table.js";
3
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "./table.js";
4
4
  /**
5
5
  * The frame every chart here sits in: a caption, a legend, the plot, and the
6
6
  * same data as a table.
@@ -20,89 +20,10 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from ".
20
20
  * swatch with text — the text is the identity channel, the swatch is the
21
21
  * cross-reference. Text never wears the series colour: a mid-lightness hue that
22
22
  * is correct for a 24px bar is unreadable at 12px.
23
- */ export function ChartFrame({ title, description, legend, table, children, className }) {
23
+ */
24
+ export function ChartFrame({ title, description, legend, table, children, className, }) {
24
25
  const showLegend = legend !== undefined && legend.length > 1;
25
- return /*#__PURE__*/ _jsxs("figure", {
26
- className: cn("flex flex-col gap-3", className),
27
- children: [
28
- /*#__PURE__*/ _jsxs("figcaption", {
29
- className: "flex flex-col gap-0.5",
30
- children: [
31
- /*#__PURE__*/ _jsx("span", {
32
- className: "text-sm font-semibold",
33
- children: title
34
- }),
35
- description === undefined ? null : /*#__PURE__*/ _jsx("span", {
36
- className: "text-xs text-muted-foreground",
37
- children: description
38
- })
39
- ]
40
- }),
41
- showLegend ? /*#__PURE__*/ _jsx("ul", {
42
- className: "flex flex-wrap items-center gap-x-4 gap-y-1",
43
- children: legend.map((entry)=>/*#__PURE__*/ _jsxs("li", {
44
- className: "flex items-center gap-1.5 text-xs text-muted-foreground",
45
- children: [
46
- entry.dash === undefined ? /*#__PURE__*/ _jsx("span", {
47
- "aria-hidden": true,
48
- className: "size-2.5 shrink-0 rounded-xs",
49
- style: {
50
- backgroundColor: entry.color
51
- }
52
- }) : /*#__PURE__*/ _jsx("svg", {
53
- "aria-hidden": true,
54
- viewBox: "0 0 20 4",
55
- className: "h-1 w-5 shrink-0 overflow-visible",
56
- children: /*#__PURE__*/ _jsx("line", {
57
- x1: 0,
58
- y1: 2,
59
- x2: 20,
60
- y2: 2,
61
- stroke: entry.color,
62
- strokeWidth: 2.5,
63
- strokeLinecap: "butt",
64
- strokeDasharray: entry.dash
65
- })
66
- }),
67
- entry.label
68
- ]
69
- }, entry.label))
70
- }) : null,
71
- children,
72
- /*#__PURE__*/ _jsxs("details", {
73
- className: "text-xs",
74
- children: [
75
- /*#__PURE__*/ _jsx("summary", {
76
- className: "cursor-pointer text-muted-foreground hover:text-foreground",
77
- children: "Show the data"
78
- }),
79
- /*#__PURE__*/ _jsx("div", {
80
- className: "mt-2",
81
- children: /*#__PURE__*/ _jsxs(Table, {
82
- "aria-label": `${title} — data`,
83
- children: [
84
- /*#__PURE__*/ _jsx(TableHeader, {
85
- children: /*#__PURE__*/ _jsx(TableRow, {
86
- children: table.columns.map((column, index)=>/*#__PURE__*/ _jsx(TableHead, {
87
- scope: "col",
88
- className: index === 0 ? undefined : "text-right",
89
- children: column
90
- }, column))
91
- })
92
- }),
93
- /*#__PURE__*/ _jsx(TableBody, {
94
- children: table.rows.map((row, rowIndex)=>/*#__PURE__*/ _jsx(TableRow, {
95
- children: row.map((cell, cellIndex)=>/*#__PURE__*/ _jsx(TableCell, {
96
- className: cellIndex === 0 ? undefined : "text-right font-mono tabular-nums",
97
- children: cell
98
- }, cellIndex))
99
- }, rowIndex))
100
- })
101
- ]
102
- })
103
- })
104
- ]
105
- })
106
- ]
107
- });
26
+ return (_jsxs("figure", { className: cn("flex flex-col gap-3", className), children: [_jsxs("figcaption", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-sm font-semibold", children: title }), description === undefined ? null : (_jsx("span", { className: "text-xs text-muted-foreground", children: description }))] }), showLegend ? (_jsx("ul", { className: "flex flex-wrap items-center gap-x-4 gap-y-1", children: legend.map((entry) => (_jsxs("li", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [entry.dash === undefined ? (_jsx("span", { "aria-hidden": true, className: "size-2.5 shrink-0 rounded-xs", style: { backgroundColor: entry.color } })) : (_jsx("svg", { "aria-hidden": true, viewBox: "0 0 20 4", className: "h-1 w-5 shrink-0 overflow-visible", children: _jsx("line", { x1: 0, y1: 2, x2: 20, y2: 2, stroke: entry.color, strokeWidth: 2.5, strokeLinecap: "butt", strokeDasharray: entry.dash }) })), entry.label] }, entry.label))) })) : null, children, _jsxs("details", { className: "text-xs", children: [_jsx("summary", { className: "cursor-pointer text-muted-foreground hover:text-foreground", children: "Show the data" }), _jsx("div", { className: "mt-2", children: _jsxs(Table, { "aria-label": `${title} — data`, children: [_jsx(TableHeader, { children: _jsx(TableRow, { children: table.columns.map((column, index) => (_jsx(TableHead, { scope: "col", className: index === 0 ? undefined : "text-right", children: column }, column))) }) }), _jsx(TableBody, { children: table.rows.map((row, rowIndex) => (_jsx(TableRow, { children: row.map((cell, cellIndex) => (_jsx(TableCell, { className: cellIndex === 0
27
+ ? undefined
28
+ : "text-right font-mono tabular-nums", children: cell }, cellIndex))) }, rowIndex))) })] }) })] })] }));
108
29
  }
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useRef } from "react";
3
4
  import { useDelayedAutofocus } from "../hooks/use-delayed-autofocus.js";
@@ -10,23 +11,10 @@ import { QuickReplyChips } from "./quick-reply-chips.js";
10
11
  * always-on, because a suggestion list next to ten prior turns is not a
11
12
  * suggestion anymore — it is clutter competing with what the user already
12
13
  * said.
13
- */ export function ChatComposer({ suggestions = [], onSuggestionSelect, busy = false, autoFocusOn = false, className, ...inputProps }) {
14
+ */
15
+ export function ChatComposer({ suggestions = [], onSuggestionSelect, busy = false, autoFocusOn = false, className, ...inputProps }) {
14
16
  const textareaRef = useRef(null);
15
17
  useDelayedAutofocus(textareaRef, autoFocusOn);
16
18
  const showSuggestions = suggestions.length > 0 && onSuggestionSelect !== undefined;
17
- return /*#__PURE__*/ _jsxs("div", {
18
- className: cn("flex flex-col gap-2", className),
19
- children: [
20
- showSuggestions ? /*#__PURE__*/ _jsx(QuickReplyChips, {
21
- replies: suggestions,
22
- onSelect: onSuggestionSelect
23
- }) : null,
24
- /*#__PURE__*/ _jsx(ChatInput, {
25
- ...inputProps,
26
- working: busy,
27
- disabled: busy,
28
- textareaRef: textareaRef
29
- })
30
- ]
31
- });
19
+ return (_jsxs("div", { className: cn("flex flex-col gap-2", className), children: [showSuggestions ? (_jsx(QuickReplyChips, { replies: suggestions, onSelect: onSuggestionSelect })) : null, _jsx(ChatInput, { ...inputProps, working: busy, disabled: busy, textareaRef: textareaRef })] }));
32
20
  }
@@ -2,10 +2,14 @@
2
2
  * The dock's one source of truth for motion timing. Every duration that has
3
3
  * to line up with another — the entrance pop, the scrim fade, the autofocus
4
4
  * delay — lives here so fixing one never means hunting the others down.
5
- */ /** How long the closed→docked entrance pop takes, in milliseconds. */ export const CHAT_DOCK_ENTRANCE_MS = 280;
6
- /** The scrim's own fade, coordinated to finish alongside the entrance. */ export const CHAT_DOCK_SCRIM_MS = CHAT_DOCK_ENTRANCE_MS;
5
+ */
6
+ /** How long the closed→docked entrance pop takes, in milliseconds. */
7
+ export const CHAT_DOCK_ENTRANCE_MS = 280;
8
+ /** The scrim's own fade, coordinated to finish alongside the entrance. */
9
+ export const CHAT_DOCK_SCRIM_MS = CHAT_DOCK_ENTRANCE_MS;
7
10
  /**
8
11
  * The composer's autofocus delay. Must be `>=` the entrance duration — focus
9
12
  * landing before the panel has finished animating steals the caret out from
10
13
  * under a still-moving element.
11
- */ export const CHAT_DOCK_AUTOFOCUS_DELAY_MS = CHAT_DOCK_ENTRANCE_MS;
14
+ */
15
+ export const CHAT_DOCK_AUTOFOCUS_DELAY_MS = CHAT_DOCK_ENTRANCE_MS;