@corbits/react-ui 0.1.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 (255) hide show
  1. package/LICENSE +501 -0
  2. package/README.md +125 -0
  3. package/dist/blocks/login/auth-layout.d.ts +38 -0
  4. package/dist/blocks/login/auth-layout.js +52 -0
  5. package/dist/blocks/login/login-form.d.ts +60 -0
  6. package/dist/blocks/login/login-form.js +151 -0
  7. package/dist/hooks/use-command-palette-navigation.d.ts +25 -0
  8. package/dist/hooks/use-command-palette-navigation.js +52 -0
  9. package/dist/hooks/use-controllable-state.d.ts +28 -0
  10. package/dist/hooks/use-controllable-state.js +44 -0
  11. package/dist/hooks/use-delayed-autofocus.d.ts +9 -0
  12. package/dist/hooks/use-delayed-autofocus.js +20 -0
  13. package/dist/hooks/use-dismissable-popover.d.ts +37 -0
  14. package/dist/hooks/use-dismissable-popover.js +64 -0
  15. package/dist/hooks/use-list-selection.d.ts +66 -0
  16. package/dist/hooks/use-list-selection.js +147 -0
  17. package/dist/hooks/use-prefers-reduced-motion.d.ts +13 -0
  18. package/dist/hooks/use-prefers-reduced-motion.js +28 -0
  19. package/dist/hooks/use-scroll-current-into-view.d.ts +19 -0
  20. package/dist/hooks/use-scroll-current-into-view.js +33 -0
  21. package/dist/index.d.ts +122 -0
  22. package/dist/index.js +131 -0
  23. package/dist/lib/artifact.d.ts +72 -0
  24. package/dist/lib/artifact.js +67 -0
  25. package/dist/lib/chart-geometry.d.ts +62 -0
  26. package/dist/lib/chart-geometry.js +86 -0
  27. package/dist/lib/chart-palette.d.ts +76 -0
  28. package/dist/lib/chart-palette.js +92 -0
  29. package/dist/lib/chat-message.d.ts +115 -0
  30. package/dist/lib/chat-message.js +41 -0
  31. package/dist/lib/chat-parts.d.ts +64 -0
  32. package/dist/lib/chat-parts.js +16 -0
  33. package/dist/lib/csv.d.ts +60 -0
  34. package/dist/lib/csv.js +108 -0
  35. package/dist/lib/metrics.d.ts +70 -0
  36. package/dist/lib/metrics.js +101 -0
  37. package/dist/lib/now-item.d.ts +65 -0
  38. package/dist/lib/now-item.js +59 -0
  39. package/dist/lib/relative-time.d.ts +9 -0
  40. package/dist/lib/relative-time.js +47 -0
  41. package/dist/lib/theme.d.ts +30 -0
  42. package/dist/lib/theme.js +77 -0
  43. package/dist/lib/url.d.ts +26 -0
  44. package/dist/lib/url.js +37 -0
  45. package/dist/lib/utils.d.ts +2 -0
  46. package/dist/lib/utils.js +5 -0
  47. package/dist/lib/workflow-display-flow.d.ts +83 -0
  48. package/dist/lib/workflow-display-flow.js +104 -0
  49. package/dist/lib/workflow-registry.d.ts +90 -0
  50. package/dist/lib/workflow-registry.js +56 -0
  51. package/dist/lib/workflow-run-error.d.ts +31 -0
  52. package/dist/lib/workflow-run-error.js +105 -0
  53. package/dist/lib/workflow-run-progress.d.ts +97 -0
  54. package/dist/lib/workflow-run-progress.js +135 -0
  55. package/dist/lib/workflow-run.d.ts +43 -0
  56. package/dist/lib/workflow-run.js +56 -0
  57. package/dist/styles.css +3080 -0
  58. package/dist/test/render-hook.d.ts +14 -0
  59. package/dist/test/render-hook.js +38 -0
  60. package/dist/theme.css +628 -0
  61. package/dist/ui/agent-turn.d.ts +26 -0
  62. package/dist/ui/agent-turn.js +60 -0
  63. package/dist/ui/animated-number.d.ts +25 -0
  64. package/dist/ui/animated-number.js +63 -0
  65. package/dist/ui/approval-card.d.ts +46 -0
  66. package/dist/ui/approval-card.js +116 -0
  67. package/dist/ui/artifact-body.d.ts +26 -0
  68. package/dist/ui/artifact-body.js +170 -0
  69. package/dist/ui/artifact-notice.d.ts +21 -0
  70. package/dist/ui/artifact-notice.js +36 -0
  71. package/dist/ui/avatar.d.ts +37 -0
  72. package/dist/ui/avatar.js +73 -0
  73. package/dist/ui/badge.d.ts +10 -0
  74. package/dist/ui/badge.js +35 -0
  75. package/dist/ui/bar-chart.d.ts +38 -0
  76. package/dist/ui/bar-chart.js +118 -0
  77. package/dist/ui/block-card.d.ts +29 -0
  78. package/dist/ui/block-card.js +66 -0
  79. package/dist/ui/boot-screen.d.ts +23 -0
  80. package/dist/ui/boot-screen.js +49 -0
  81. package/dist/ui/bulk-action-bar.d.ts +37 -0
  82. package/dist/ui/bulk-action-bar.js +64 -0
  83. package/dist/ui/button.d.ts +12 -0
  84. package/dist/ui/button.js +73 -0
  85. package/dist/ui/card.d.ts +6 -0
  86. package/dist/ui/card.js +37 -0
  87. package/dist/ui/category-bars.d.ts +20 -0
  88. package/dist/ui/category-bars.js +69 -0
  89. package/dist/ui/chart-frame.d.ts +54 -0
  90. package/dist/ui/chart-frame.js +108 -0
  91. package/dist/ui/chat-composer.d.ts +24 -0
  92. package/dist/ui/chat-composer.js +32 -0
  93. package/dist/ui/chat-dock-timing.d.ts +15 -0
  94. package/dist/ui/chat-dock-timing.js +11 -0
  95. package/dist/ui/chat-input.d.ts +38 -0
  96. package/dist/ui/chat-input.js +138 -0
  97. package/dist/ui/chat-panel.d.ts +20 -0
  98. package/dist/ui/chat-panel.js +56 -0
  99. package/dist/ui/chat-thread.d.ts +28 -0
  100. package/dist/ui/chat-thread.js +61 -0
  101. package/dist/ui/checkbox.d.ts +25 -0
  102. package/dist/ui/checkbox.js +63 -0
  103. package/dist/ui/command-palette.d.ts +100 -0
  104. package/dist/ui/command-palette.js +341 -0
  105. package/dist/ui/compare-body.d.ts +52 -0
  106. package/dist/ui/compare-body.js +140 -0
  107. package/dist/ui/confirm-button.d.ts +29 -0
  108. package/dist/ui/confirm-button.js +41 -0
  109. package/dist/ui/corbits-mark.d.ts +29 -0
  110. package/dist/ui/corbits-mark.js +33 -0
  111. package/dist/ui/csv-table.d.ts +22 -0
  112. package/dist/ui/csv-table.js +85 -0
  113. package/dist/ui/dialog.d.ts +37 -0
  114. package/dist/ui/dialog.js +105 -0
  115. package/dist/ui/dictation-status-line.d.ts +20 -0
  116. package/dist/ui/dictation-status-line.js +38 -0
  117. package/dist/ui/dither-canvas.d.ts +31 -0
  118. package/dist/ui/dither-canvas.js +169 -0
  119. package/dist/ui/embed-body.d.ts +30 -0
  120. package/dist/ui/embed-body.js +92 -0
  121. package/dist/ui/empty-state.d.ts +26 -0
  122. package/dist/ui/empty-state.js +42 -0
  123. package/dist/ui/file-input.d.ts +25 -0
  124. package/dist/ui/file-input.js +66 -0
  125. package/dist/ui/filter-bar.d.ts +42 -0
  126. package/dist/ui/filter-bar.js +95 -0
  127. package/dist/ui/filter-chip.d.ts +14 -0
  128. package/dist/ui/filter-chip.js +23 -0
  129. package/dist/ui/gate-block.d.ts +16 -0
  130. package/dist/ui/gate-block.js +37 -0
  131. package/dist/ui/horizontal-stepper.d.ts +13 -0
  132. package/dist/ui/horizontal-stepper.js +65 -0
  133. package/dist/ui/input.d.ts +2 -0
  134. package/dist/ui/input.js +14 -0
  135. package/dist/ui/inspector-shell.d.ts +47 -0
  136. package/dist/ui/inspector-shell.js +98 -0
  137. package/dist/ui/intake-form.d.ts +39 -0
  138. package/dist/ui/intake-form.js +119 -0
  139. package/dist/ui/kind-card-grid.d.ts +23 -0
  140. package/dist/ui/kind-card-grid.js +43 -0
  141. package/dist/ui/library-page-header.d.ts +20 -0
  142. package/dist/ui/library-page-header.js +43 -0
  143. package/dist/ui/list-detail.d.ts +28 -0
  144. package/dist/ui/list-detail.js +55 -0
  145. package/dist/ui/live-run-banner.d.ts +13 -0
  146. package/dist/ui/live-run-banner.js +23 -0
  147. package/dist/ui/live-status-line.d.ts +22 -0
  148. package/dist/ui/live-status-line.js +37 -0
  149. package/dist/ui/menu.d.ts +18 -0
  150. package/dist/ui/menu.js +45 -0
  151. package/dist/ui/message-bubble.d.ts +24 -0
  152. package/dist/ui/message-bubble.js +64 -0
  153. package/dist/ui/mic-button.d.ts +35 -0
  154. package/dist/ui/mic-button.js +61 -0
  155. package/dist/ui/mic-permission-dialog.d.ts +20 -0
  156. package/dist/ui/mic-permission-dialog.js +50 -0
  157. package/dist/ui/notifications-bell.d.ts +28 -0
  158. package/dist/ui/notifications-bell.js +69 -0
  159. package/dist/ui/now-cards.d.ts +37 -0
  160. package/dist/ui/now-cards.js +116 -0
  161. package/dist/ui/page-panel.d.ts +37 -0
  162. package/dist/ui/page-panel.js +23 -0
  163. package/dist/ui/page-shell.d.ts +21 -0
  164. package/dist/ui/page-shell.js +26 -0
  165. package/dist/ui/parts-renderer.d.ts +22 -0
  166. package/dist/ui/parts-renderer.js +234 -0
  167. package/dist/ui/profile-card.d.ts +39 -0
  168. package/dist/ui/profile-card.js +124 -0
  169. package/dist/ui/progress-checklist.d.ts +25 -0
  170. package/dist/ui/progress-checklist.js +70 -0
  171. package/dist/ui/provider-mark.d.ts +32 -0
  172. package/dist/ui/provider-mark.js +31 -0
  173. package/dist/ui/quick-reply-chips.d.ts +14 -0
  174. package/dist/ui/quick-reply-chips.js +24 -0
  175. package/dist/ui/quote-card.d.ts +39 -0
  176. package/dist/ui/quote-card.js +66 -0
  177. package/dist/ui/reasoning-block.d.ts +35 -0
  178. package/dist/ui/reasoning-block.js +60 -0
  179. package/dist/ui/research-body.d.ts +70 -0
  180. package/dist/ui/research-body.js +270 -0
  181. package/dist/ui/rich-empty-state.d.ts +35 -0
  182. package/dist/ui/rich-empty-state.js +65 -0
  183. package/dist/ui/run-now-button.d.ts +23 -0
  184. package/dist/ui/run-now-button.js +42 -0
  185. package/dist/ui/section.d.ts +20 -0
  186. package/dist/ui/section.js +48 -0
  187. package/dist/ui/select.d.ts +2 -0
  188. package/dist/ui/select.js +22 -0
  189. package/dist/ui/selection-checkbox.d.ts +42 -0
  190. package/dist/ui/selection-checkbox.js +54 -0
  191. package/dist/ui/settings-panel.d.ts +35 -0
  192. package/dist/ui/settings-panel.js +68 -0
  193. package/dist/ui/shimmer-text.d.ts +19 -0
  194. package/dist/ui/shimmer-text.js +20 -0
  195. package/dist/ui/sidebar-item-row.d.ts +40 -0
  196. package/dist/ui/sidebar-item-row.js +64 -0
  197. package/dist/ui/sidebar-panel.d.ts +25 -0
  198. package/dist/ui/sidebar-panel.js +56 -0
  199. package/dist/ui/sidebar.d.ts +46 -0
  200. package/dist/ui/sidebar.js +111 -0
  201. package/dist/ui/skeleton.d.ts +13 -0
  202. package/dist/ui/skeleton.js +20 -0
  203. package/dist/ui/sortable-table.d.ts +43 -0
  204. package/dist/ui/sortable-table.js +103 -0
  205. package/dist/ui/sparkline.d.ts +27 -0
  206. package/dist/ui/sparkline.js +68 -0
  207. package/dist/ui/stat-grid.d.ts +55 -0
  208. package/dist/ui/stat-grid.js +87 -0
  209. package/dist/ui/status-dot.d.ts +13 -0
  210. package/dist/ui/status-dot.js +51 -0
  211. package/dist/ui/step-list.d.ts +21 -0
  212. package/dist/ui/step-list.js +77 -0
  213. package/dist/ui/switch.d.ts +23 -0
  214. package/dist/ui/switch.js +29 -0
  215. package/dist/ui/table.d.ts +8 -0
  216. package/dist/ui/table.js +48 -0
  217. package/dist/ui/tabs.d.ts +44 -0
  218. package/dist/ui/tabs.js +101 -0
  219. package/dist/ui/textarea.d.ts +8 -0
  220. package/dist/ui/textarea.js +32 -0
  221. package/dist/ui/theme-provider.d.ts +36 -0
  222. package/dist/ui/theme-provider.js +126 -0
  223. package/dist/ui/theme-toggle.d.ts +11 -0
  224. package/dist/ui/theme-toggle.js +32 -0
  225. package/dist/ui/thinking-indicator.d.ts +7 -0
  226. package/dist/ui/thinking-indicator.js +19 -0
  227. package/dist/ui/thinking-label.d.ts +19 -0
  228. package/dist/ui/thinking-label.js +54 -0
  229. package/dist/ui/thinking-mark.d.ts +10 -0
  230. package/dist/ui/thinking-mark.js +153 -0
  231. package/dist/ui/time-series-chart.d.ts +55 -0
  232. package/dist/ui/time-series-chart.js +249 -0
  233. package/dist/ui/toast.d.ts +16 -0
  234. package/dist/ui/toast.js +41 -0
  235. package/dist/ui/token-mosaic.d.ts +22 -0
  236. package/dist/ui/token-mosaic.js +65 -0
  237. package/dist/ui/tool-block.d.ts +54 -0
  238. package/dist/ui/tool-block.js +170 -0
  239. package/dist/ui/tool-narrative.d.ts +22 -0
  240. package/dist/ui/tool-narrative.js +77 -0
  241. package/dist/ui/tool-picker.d.ts +44 -0
  242. package/dist/ui/tool-picker.js +200 -0
  243. package/dist/ui/tooltip.d.ts +21 -0
  244. package/dist/ui/tooltip.js +48 -0
  245. package/dist/ui/top-bar.d.ts +53 -0
  246. package/dist/ui/top-bar.js +98 -0
  247. package/dist/ui/trace-waterfall.d.ts +38 -0
  248. package/dist/ui/trace-waterfall.js +121 -0
  249. package/dist/ui/typing-indicator.d.ts +9 -0
  250. package/dist/ui/typing-indicator.js +25 -0
  251. package/dist/ui/view-toggle.d.ts +17 -0
  252. package/dist/ui/view-toggle.js +46 -0
  253. package/dist/ui/voice-waveform.d.ts +16 -0
  254. package/dist/ui/voice-waveform.js +23 -0
  255. package/package.json +583 -0
@@ -0,0 +1,98 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronRight } from "lucide-react";
3
+ import { cn } from "../lib/utils.js";
4
+ /**
5
+ * The row above the page. It owns no content of its own — a title or a
6
+ * breadcrumb trail on the left, whatever the page contributes on the right.
7
+ *
8
+ * Deliberately a `<header>` with parts rather than a `title`/`actions` prop
9
+ * pair: pages need a search box, a filter row or a context strip in that space,
10
+ * and a fixed prop list would push every one of them through a `ReactNode` prop
11
+ * that does the same job as a child.
12
+ */ export function TopBar({ className, ...props }) {
13
+ return /*#__PURE__*/ _jsx("header", {
14
+ "data-slot": "top-bar",
15
+ className: cn("flex min-h-14 shrink-0 flex-wrap items-center gap-3 border-b border-border px-4 py-2", className),
16
+ ...props
17
+ });
18
+ }
19
+ export function TopBarTitle({ count, subtitle, className, children, ...props }) {
20
+ return /*#__PURE__*/ _jsxs("div", {
21
+ "data-slot": "top-bar-title",
22
+ className: cn("flex min-w-0 shrink items-center gap-2", className),
23
+ ...props,
24
+ children: [
25
+ /*#__PURE__*/ _jsxs("div", {
26
+ className: "flex min-w-0 flex-col",
27
+ children: [
28
+ /*#__PURE__*/ _jsx("h1", {
29
+ className: "truncate text-base font-semibold tracking-tight",
30
+ children: children
31
+ }),
32
+ subtitle === undefined ? null : /*#__PURE__*/ _jsx("p", {
33
+ className: "truncate text-xs text-muted-foreground",
34
+ children: subtitle
35
+ })
36
+ ]
37
+ }),
38
+ count === undefined ? null : /*#__PURE__*/ _jsx("span", {
39
+ className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-mono text-xs text-muted-foreground",
40
+ children: count
41
+ })
42
+ ]
43
+ });
44
+ }
45
+ function DefaultBreadcrumbLink({ href, className, children }) {
46
+ return /*#__PURE__*/ _jsx("a", {
47
+ href: href,
48
+ className: className,
49
+ children: children
50
+ });
51
+ }
52
+ /**
53
+ * Breadcrumb trail. The last crumb is the current page: it is rendered as text
54
+ * with `aria-current="page"` even if a caller passes an href, because linking
55
+ * to where you already are is a known screen-reader annoyance.
56
+ *
57
+ * Every other crumb renders through `linkComponent`, defaulting to a plain
58
+ * `<a>`. A consumer routing through a SPA router passes its own `Link` so a
59
+ * breadcrumb click does not force a full page reload.
60
+ */ export function TopBarBreadcrumbs({ crumbs, linkComponent: LinkComponent = DefaultBreadcrumbLink, className, ...props }) {
61
+ return /*#__PURE__*/ _jsx("nav", {
62
+ "data-slot": "top-bar-breadcrumbs",
63
+ "aria-label": "Breadcrumb",
64
+ className: cn("min-w-0", className),
65
+ ...props,
66
+ children: /*#__PURE__*/ _jsx("ol", {
67
+ className: "flex min-w-0 items-center gap-1 text-sm",
68
+ children: crumbs.map((crumb, index)=>{
69
+ const isLast = index === crumbs.length - 1;
70
+ return /*#__PURE__*/ _jsxs("li", {
71
+ className: "flex min-w-0 items-center gap-1",
72
+ children: [
73
+ index === 0 ? null : /*#__PURE__*/ _jsx(ChevronRight, {
74
+ className: "size-3.5 shrink-0 text-muted-foreground",
75
+ "aria-hidden": true
76
+ }),
77
+ isLast || crumb.href === undefined ? /*#__PURE__*/ _jsx("span", {
78
+ "aria-current": isLast ? "page" : undefined,
79
+ className: cn("truncate", isLast ? "font-medium" : "text-muted-foreground"),
80
+ children: crumb.label
81
+ }) : /*#__PURE__*/ _jsx(LinkComponent, {
82
+ href: crumb.href,
83
+ className: "truncate text-muted-foreground hover:text-foreground",
84
+ children: crumb.label
85
+ })
86
+ ]
87
+ }, index);
88
+ })
89
+ })
90
+ });
91
+ }
92
+ /** Trailing controls. Pushes itself to the right; put it last. */ export function TopBarActions({ className, ...props }) {
93
+ return /*#__PURE__*/ _jsx("div", {
94
+ "data-slot": "top-bar-actions",
95
+ className: cn("ml-auto flex shrink-0 items-center gap-1", className),
96
+ ...props
97
+ });
98
+ }
@@ -0,0 +1,38 @@
1
+ export type TracePhase = "ok" | "awaiting" | "failed";
2
+ export type TraceSpan = {
3
+ readonly id: string;
4
+ readonly label: string;
5
+ readonly kind: string;
6
+ /** Inclusive start as a fraction of the total timeline (0–1). */
7
+ readonly start: number;
8
+ /** Inclusive end as a fraction of the total timeline (0–1). */
9
+ readonly end: number;
10
+ readonly durationLabel: string | null;
11
+ readonly tokensLabel?: string;
12
+ readonly phase: TracePhase;
13
+ readonly error?: string;
14
+ /**
15
+ * How `start`/`end` were derived. "measured" (the default when omitted)
16
+ * means real wall-clock timing, rendered as a proportional duration bar.
17
+ * "ordinal" means the span was positioned only by event order within its
18
+ * parent, with no real duration — it renders as a point marker at `start`
19
+ * instead of a bar spanning start→end, so the chart never implies a
20
+ * duration the data doesn't have.
21
+ */
22
+ readonly timingSource?: "measured" | "ordinal";
23
+ };
24
+ export type TraceWaterfallProps = {
25
+ readonly title: string;
26
+ readonly description?: string;
27
+ readonly spans: readonly TraceSpan[];
28
+ readonly className?: string;
29
+ };
30
+ /**
31
+ * Run-trace timeline: one row per span with a duration, and optional token
32
+ * count. A span with real wall-clock timing renders a proportional bar; a
33
+ * span positioned only by event order (`timingSource: "ordinal"`) renders a
34
+ * point marker instead, so the chart never implies a duration the data
35
+ * doesn't have. Failed spans surface their error under the row. The
36
+ * accessible table carries the same numbers for non-visual readers.
37
+ */
38
+ export declare function TraceWaterfall({ title, description, spans, className }: TraceWaterfallProps): import("react").JSX.Element;
@@ -0,0 +1,121 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/utils.js";
3
+ import { ChartFrame } from "./chart-frame.js";
4
+ const PHASE_FILL = {
5
+ ok: "bg-success-foreground",
6
+ awaiting: "bg-warning-foreground",
7
+ failed: "bg-destructive"
8
+ };
9
+ const PHASE_LABEL = {
10
+ ok: "ok",
11
+ awaiting: "awaiting",
12
+ failed: "failed"
13
+ };
14
+ /**
15
+ * Run-trace timeline: one row per span with a duration, and optional token
16
+ * count. A span with real wall-clock timing renders a proportional bar; a
17
+ * span positioned only by event order (`timingSource: "ordinal"`) renders a
18
+ * point marker instead, so the chart never implies a duration the data
19
+ * doesn't have. Failed spans surface their error under the row. The
20
+ * accessible table carries the same numbers for non-visual readers.
21
+ */ export function TraceWaterfall({ title, description, spans, className }) {
22
+ return /*#__PURE__*/ _jsx(ChartFrame, {
23
+ title: title,
24
+ ...description === undefined ? {} : {
25
+ description
26
+ },
27
+ table: {
28
+ columns: [
29
+ "Step",
30
+ "Kind",
31
+ "Duration",
32
+ "Tokens",
33
+ "Status"
34
+ ],
35
+ rows: spans.map((span)=>[
36
+ span.label,
37
+ span.kind,
38
+ durationText(span.durationLabel),
39
+ span.tokensLabel ?? "—",
40
+ PHASE_LABEL[span.phase]
41
+ ])
42
+ },
43
+ className: className,
44
+ children: /*#__PURE__*/ _jsx("div", {
45
+ className: "flex flex-col gap-1.5",
46
+ role: "presentation",
47
+ children: spans.map((span)=>{
48
+ const isOrdinal = span.timingSource === "ordinal";
49
+ const left = clamp01(span.start) * 100;
50
+ const width = Math.max(0.5, (clamp01(span.end) - clamp01(span.start)) * 100);
51
+ return /*#__PURE__*/ _jsxs("div", {
52
+ className: "flex flex-col gap-0.5",
53
+ children: [
54
+ /*#__PURE__*/ _jsxs("div", {
55
+ className: "grid grid-cols-[minmax(7rem,11rem)_1fr_minmax(4.5rem,6rem)] items-center gap-2",
56
+ children: [
57
+ /*#__PURE__*/ _jsxs("div", {
58
+ className: "min-w-0",
59
+ children: [
60
+ /*#__PURE__*/ _jsx("p", {
61
+ className: "truncate text-xs font-semibold",
62
+ children: span.label
63
+ }),
64
+ /*#__PURE__*/ _jsx("p", {
65
+ className: "truncate text-[10px] text-muted-foreground",
66
+ children: span.kind
67
+ })
68
+ ]
69
+ }),
70
+ /*#__PURE__*/ _jsx("div", {
71
+ className: "relative h-4 w-full bg-muted",
72
+ children: isOrdinal ? /*#__PURE__*/ _jsx("span", {
73
+ className: cn("absolute top-1/2 size-2.5 -translate-x-1/2 -translate-y-1/2 rotate-45", PHASE_FILL[span.phase]),
74
+ style: {
75
+ left: `${left}%`
76
+ },
77
+ children: /*#__PURE__*/ _jsx("span", {
78
+ className: "sr-only",
79
+ children: "Approximate position by event order, not a measured duration"
80
+ })
81
+ }) : /*#__PURE__*/ _jsx("div", {
82
+ className: cn("absolute inset-y-0", PHASE_FILL[span.phase], span.phase === "awaiting" && "[background-image:repeating-linear-gradient(135deg,transparent,transparent_3px,rgba(0,0,0,0.15)_3px,rgba(0,0,0,0.15)_6px)]"),
83
+ style: {
84
+ left: `${left}%`,
85
+ width: `${width}%`
86
+ }
87
+ })
88
+ }),
89
+ /*#__PURE__*/ _jsxs("div", {
90
+ className: "text-right font-mono text-[11px] leading-tight",
91
+ children: [
92
+ /*#__PURE__*/ _jsx("p", {
93
+ className: "font-semibold",
94
+ children: durationText(span.durationLabel)
95
+ }),
96
+ span.tokensLabel === undefined ? null : /*#__PURE__*/ _jsx("p", {
97
+ className: "text-muted-foreground",
98
+ children: span.tokensLabel
99
+ })
100
+ ]
101
+ })
102
+ ]
103
+ }),
104
+ span.error === undefined ? null : /*#__PURE__*/ _jsx("p", {
105
+ className: "ml-[11.5rem] border border-destructive/40 bg-destructive/10 px-2 py-1 text-[11px] text-destructive-foreground",
106
+ children: span.error
107
+ })
108
+ ]
109
+ }, span.id);
110
+ })
111
+ })
112
+ });
113
+ }
114
+ function durationText(durationLabel) {
115
+ return durationLabel ?? "—";
116
+ }
117
+ function clamp01(value) {
118
+ if (value < 0) return 0;
119
+ if (value > 1) return 1;
120
+ return value;
121
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Three pulsing dots: the agent is composing a reply, with nothing to report
3
+ * yet. `role="status"` with a text label, because the dots carry no words a
4
+ * screen reader can read — the label is the only accessible content here.
5
+ */
6
+ export declare function TypingIndicator({ label, className }: {
7
+ label?: string;
8
+ className?: string;
9
+ }): import("react").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "../lib/utils.js";
3
+ const DOT_DELAY_MS = [
4
+ 0,
5
+ 160,
6
+ 320
7
+ ];
8
+ /**
9
+ * Three pulsing dots: the agent is composing a reply, with nothing to report
10
+ * yet. `role="status"` with a text label, because the dots carry no words a
11
+ * screen reader can read — the label is the only accessible content here.
12
+ */ export function TypingIndicator({ label = "Thinking", className }) {
13
+ return /*#__PURE__*/ _jsx("div", {
14
+ role: "status",
15
+ "aria-label": label,
16
+ className: cn("flex items-center gap-1 px-1 py-2", className),
17
+ children: DOT_DELAY_MS.map((delay)=>/*#__PURE__*/ _jsx("span", {
18
+ "aria-hidden": true,
19
+ style: {
20
+ animationDelay: `${delay}ms`
21
+ },
22
+ className: "size-1.5 rounded-full bg-muted-foreground [animation:corbits-typing-bounce_1.2s_ease-in-out_infinite]"
23
+ }, delay))
24
+ });
25
+ }
@@ -0,0 +1,17 @@
1
+ export type ViewMode = "grid" | "rows";
2
+ /**
3
+ * Grid or rows, as a segmented control.
4
+ *
5
+ * `role="group"` with `aria-pressed` toggles rather than a radiogroup: these
6
+ * are two buttons that change a view, and radios promise arrow-key navigation
7
+ * between options plus form-submission semantics that do not apply.
8
+ *
9
+ * Each button carries a text label for assistive tech; the icon alone is not a
10
+ * name. Stateless — the page owns `mode`, because the choice usually outlives
11
+ * the component and gets persisted.
12
+ */
13
+ export declare function ViewToggle({ mode, onChange, className, }: {
14
+ mode: ViewMode;
15
+ onChange: (mode: ViewMode) => void;
16
+ className?: string;
17
+ }): import("react").JSX.Element;
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { LayoutGrid, Rows3 } from "lucide-react";
3
+ import { cn } from "../lib/utils.js";
4
+ const OPTIONS = [
5
+ {
6
+ mode: "grid",
7
+ label: "Grid view",
8
+ Icon: LayoutGrid
9
+ },
10
+ {
11
+ mode: "rows",
12
+ label: "Rows view",
13
+ Icon: Rows3
14
+ }
15
+ ];
16
+ /**
17
+ * Grid or rows, as a segmented control.
18
+ *
19
+ * `role="group"` with `aria-pressed` toggles rather than a radiogroup: these
20
+ * are two buttons that change a view, and radios promise arrow-key navigation
21
+ * between options plus form-submission semantics that do not apply.
22
+ *
23
+ * Each button carries a text label for assistive tech; the icon alone is not a
24
+ * name. Stateless — the page owns `mode`, because the choice usually outlives
25
+ * the component and gets persisted.
26
+ */ export function ViewToggle({ mode, onChange, className }) {
27
+ return /*#__PURE__*/ _jsx("div", {
28
+ role: "group",
29
+ "aria-label": "View",
30
+ className: cn("flex items-center gap-0.5 rounded-md border border-border p-0.5", className),
31
+ children: OPTIONS.map(({ mode: option, label, Icon })=>{
32
+ const active = mode === option;
33
+ return /*#__PURE__*/ _jsx("button", {
34
+ type: "button",
35
+ "aria-label": label,
36
+ "aria-pressed": active,
37
+ onClick: ()=>onChange(option),
38
+ className: cn("grid size-7 place-items-center rounded-sm transition-colors", active ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"),
39
+ children: /*#__PURE__*/ _jsx(Icon, {
40
+ className: "size-4",
41
+ "aria-hidden": true
42
+ })
43
+ }, option);
44
+ })
45
+ });
46
+ }
@@ -0,0 +1,16 @@
1
+ export type VoiceWaveformProps = {
2
+ /** Recent input levels, 0..1, oldest first. One bar per entry. */
3
+ readonly levels: readonly number[];
4
+ readonly className?: string;
5
+ };
6
+ /**
7
+ * A bar waveform driven entirely by `levels` — no microphone or audio API
8
+ * here, the consumer's dictation hook owns sampling and passes the numbers
9
+ * in. `aria-hidden`: the state it shows is spoken separately by
10
+ * `DictationStatusLine`.
11
+ *
12
+ * Bar height is an inline `scaleY` transform per frame; the `duration-75`
13
+ * transition is plain CSS, so the theme's global reduced-motion rule already
14
+ * collapses it — no JS-side handling needed here.
15
+ */
16
+ export declare function VoiceWaveform({ levels, className }: VoiceWaveformProps): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "../lib/utils.js";
3
+ /**
4
+ * A bar waveform driven entirely by `levels` — no microphone or audio API
5
+ * here, the consumer's dictation hook owns sampling and passes the numbers
6
+ * in. `aria-hidden`: the state it shows is spoken separately by
7
+ * `DictationStatusLine`.
8
+ *
9
+ * Bar height is an inline `scaleY` transform per frame; the `duration-75`
10
+ * transition is plain CSS, so the theme's global reduced-motion rule already
11
+ * collapses it — no JS-side handling needed here.
12
+ */ export function VoiceWaveform({ levels, className }) {
13
+ return /*#__PURE__*/ _jsx("span", {
14
+ "aria-hidden": true,
15
+ className: cn("inline-flex h-4 items-center gap-px", className),
16
+ children: levels.map((level, index)=>/*#__PURE__*/ _jsx("i", {
17
+ className: "inline-block h-full w-0.5 origin-center rounded-full bg-current transition-transform duration-75",
18
+ style: {
19
+ transform: `scaleY(${Math.max(0.08, Math.min(1, level))})`
20
+ }
21
+ }, index))
22
+ });
23
+ }