@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,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/utils.js";
3
+ const SIZE_CLASS = {
4
+ sm: "size-6 text-[10px]",
5
+ md: "size-8 text-xs",
6
+ lg: "size-10 text-sm"
7
+ };
8
+ const TONE_CLASS = {
9
+ neutral: "bg-muted text-muted-foreground",
10
+ agent: "bg-primary text-primary-foreground",
11
+ agent2: "bg-accent text-accent-foreground",
12
+ agent3: "bg-success text-success-foreground"
13
+ };
14
+ const BADGE_SIZE = {
15
+ sm: "size-3 text-[7px]",
16
+ md: "size-3.5 text-[8px]",
17
+ lg: "size-4 text-[9px]"
18
+ };
19
+ /**
20
+ * Initials avatar with optional tenant monogram badge. Images are
21
+ * intentionally unsupported here: identity headers should not flash or
22
+ * depend on third-party avatar hosts.
23
+ */ export function Avatar({ initials, label, tone = "neutral", size = "md", tenantMonogram, className }) {
24
+ return /*#__PURE__*/ _jsxs("span", {
25
+ role: "img",
26
+ "aria-label": label,
27
+ className: cn("relative inline-flex shrink-0 items-center justify-center font-bold uppercase", SIZE_CLASS[size], TONE_CLASS[tone], className),
28
+ children: [
29
+ /*#__PURE__*/ _jsx("span", {
30
+ "aria-hidden": true,
31
+ children: initials.slice(0, 2)
32
+ }),
33
+ tenantMonogram === undefined ? null : /*#__PURE__*/ _jsx("span", {
34
+ "aria-hidden": true,
35
+ className: cn("absolute -right-0.5 -bottom-0.5 inline-flex items-center justify-center border border-background bg-muted font-bold uppercase text-muted-foreground", BADGE_SIZE[size]),
36
+ children: tenantMonogram.slice(0, 1)
37
+ })
38
+ ]
39
+ });
40
+ }
41
+ /**
42
+ * Overlapping avatar stack for thread participants and channel members.
43
+ */ export function AvatarStack({ items, max = 4, size = "sm", className }) {
44
+ const visible = items.slice(0, max);
45
+ const overflow = items.length - visible.length;
46
+ return /*#__PURE__*/ _jsxs("span", {
47
+ className: cn("inline-flex items-center", className),
48
+ role: "group",
49
+ "aria-label": "Participants",
50
+ children: [
51
+ visible.map((item, index)=>/*#__PURE__*/ _jsx(Avatar, {
52
+ initials: item.initials,
53
+ label: item.label,
54
+ ...item.tone === undefined ? {} : {
55
+ tone: item.tone
56
+ },
57
+ ...item.tenantMonogram === undefined ? {} : {
58
+ tenantMonogram: item.tenantMonogram
59
+ },
60
+ size: size,
61
+ className: cn("ring-1 ring-background", index > 0 && "-ml-1.5")
62
+ }, item.id)),
63
+ overflow <= 0 ? null : /*#__PURE__*/ _jsxs("span", {
64
+ className: cn("inline-flex items-center justify-center bg-muted font-mono font-semibold text-muted-foreground ring-1 ring-background", SIZE_CLASS[size], visible.length > 0 && "-ml-1.5"),
65
+ "aria-label": `${overflow} more`,
66
+ children: [
67
+ "+",
68
+ overflow
69
+ ]
70
+ })
71
+ ]
72
+ });
73
+ }
@@ -0,0 +1,10 @@
1
+ import { type VariantProps } from "class-variance-authority";
2
+ import type * as React from "react";
3
+ declare const badgeVariants: (props?: ({
4
+ tone?: "neutral" | "accent" | "info" | "success" | "warning" | "danger" | "shared" | "access" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ /** The tone names, exported so callers can type a state → tone lookup table. */
7
+ export type BadgeTone = NonNullable<VariantProps<typeof badgeVariants>["tone"]>;
8
+ export type BadgeProps = React.ComponentProps<"span"> & VariantProps<typeof badgeVariants>;
9
+ export declare function Badge({ className, tone, ...props }: BadgeProps): React.JSX.Element;
10
+ export { badgeVariants };
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import { cn } from "../lib/utils.js";
4
+ // A compact label chip. Tones are semantic, not decorative: `accent` is the one
5
+ // orange tone and — like the primary button — should stay rare on a screen.
6
+ // Orange here is `primary-emphasis`, the orange that clears text contrast on the
7
+ // page and card grounds; the fill orange does not.
8
+ const badgeVariants = cva("inline-flex items-center gap-1 rounded-sm border px-1.5 py-0.5 text-[10px] font-semibold tracking-[0.08em] uppercase", {
9
+ variants: {
10
+ tone: {
11
+ neutral: "border-border bg-muted text-muted-foreground",
12
+ accent: "border-primary-emphasis/40 bg-primary/10 text-primary-emphasis",
13
+ info: "border-accent bg-accent text-accent-foreground",
14
+ success: "border-success bg-success text-success-foreground",
15
+ // Warning reuses accent amber until a dedicated warning pair lands in theme.
16
+ warning: "border-primary-emphasis/40 bg-primary/10 text-primary-emphasis",
17
+ danger: "border-destructive bg-destructive text-destructive-foreground",
18
+ shared: "border-accent bg-accent text-accent-foreground",
19
+ access: "border-primary-emphasis/40 bg-primary/10 text-primary-emphasis"
20
+ }
21
+ },
22
+ defaultVariants: {
23
+ tone: "neutral"
24
+ }
25
+ });
26
+ export function Badge({ className, tone, ...props }) {
27
+ return /*#__PURE__*/ _jsx("span", {
28
+ "data-slot": "badge",
29
+ className: cn(badgeVariants({
30
+ tone
31
+ }), className),
32
+ ...props
33
+ });
34
+ }
35
+ export { badgeVariants };
@@ -0,0 +1,38 @@
1
+ export type BarDatum = {
2
+ readonly label: string;
3
+ readonly value: number;
4
+ };
5
+ export type BarChartProps = {
6
+ readonly title: string;
7
+ readonly description?: string;
8
+ readonly data: readonly BarDatum[];
9
+ /** Column header for the value in the table view. */
10
+ readonly valueLabel?: string;
11
+ /** Formats the value at each bar's tip and in the table. */
12
+ readonly format?: (value: number) => string;
13
+ readonly className?: string;
14
+ };
15
+ /**
16
+ * One value per category, as horizontal bars.
17
+ *
18
+ * Horizontal, not vertical, because category labels are words. Words on a
19
+ * vertical chart's x-axis either rotate 45°, truncate, or force the chart to be
20
+ * as wide as the longest name; on a horizontal chart they sit flat in a fixed
21
+ * gutter and stay readable at any count.
22
+ *
23
+ * Every bar is the *same* colour — slot 1. Colouring nominal bars by their value
24
+ * spends the identity channel re-encoding what bar length already shows, and it
25
+ * makes a legend necessary for information the reader already has. The bars are
26
+ * one series, so there is no legend either: the caption names it.
27
+ *
28
+ * The rounded end is only on the value end. A bar rounded at the baseline no
29
+ * longer starts at zero — it starts at a curve, and small values read as smaller
30
+ * than they are. `RADIUS` is also clamped to half the bar's length so a short
31
+ * bar becomes a stub rather than a lozenge whose length is pure geometry.
32
+ *
33
+ * The whole plot is `aria-hidden` and the table below the frame carries the
34
+ * numbers. An SVG full of `<rect>` elements announced individually is noise, and
35
+ * the exact values — which is what anyone reading non-visually wants — are in
36
+ * the table, in order, with headers.
37
+ */
38
+ export declare function BarChart({ title, description, data, valueLabel, format, className }: BarChartProps): import("react").JSX.Element;
@@ -0,0 +1,118 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { formatCompact, niceTicks, scaleLinear } from "../lib/chart-geometry.js";
3
+ import { seriesColor } from "../lib/chart-palette.js";
4
+ import { cn } from "../lib/utils.js";
5
+ import { ChartFrame } from "./chart-frame.js";
6
+ const ROW_HEIGHT = 28;
7
+ const BAR_HEIGHT = 20; // ≤ 24px: the band's leftover is deliberate air.
8
+ const LABEL_WIDTH = 120;
9
+ const VALUE_WIDTH = 56;
10
+ const RADIUS = 4;
11
+ /**
12
+ * One value per category, as horizontal bars.
13
+ *
14
+ * Horizontal, not vertical, because category labels are words. Words on a
15
+ * vertical chart's x-axis either rotate 45°, truncate, or force the chart to be
16
+ * as wide as the longest name; on a horizontal chart they sit flat in a fixed
17
+ * gutter and stay readable at any count.
18
+ *
19
+ * Every bar is the *same* colour — slot 1. Colouring nominal bars by their value
20
+ * spends the identity channel re-encoding what bar length already shows, and it
21
+ * makes a legend necessary for information the reader already has. The bars are
22
+ * one series, so there is no legend either: the caption names it.
23
+ *
24
+ * The rounded end is only on the value end. A bar rounded at the baseline no
25
+ * longer starts at zero — it starts at a curve, and small values read as smaller
26
+ * than they are. `RADIUS` is also clamped to half the bar's length so a short
27
+ * bar becomes a stub rather than a lozenge whose length is pure geometry.
28
+ *
29
+ * The whole plot is `aria-hidden` and the table below the frame carries the
30
+ * numbers. An SVG full of `<rect>` elements announced individually is noise, and
31
+ * the exact values — which is what anyone reading non-visually wants — are in
32
+ * the table, in order, with headers.
33
+ */ export function BarChart({ title, description, data, valueLabel = "Value", format = formatCompact, className }) {
34
+ const max = Math.max(0, ...data.map((datum)=>datum.value));
35
+ const ticks = niceTicks(max);
36
+ const axisMax = ticks[ticks.length - 1] ?? 1;
37
+ const plotWidth = 320;
38
+ const height = data.length * ROW_HEIGHT;
39
+ const width = LABEL_WIDTH + plotWidth + VALUE_WIDTH;
40
+ return /*#__PURE__*/ _jsxs(ChartFrame, {
41
+ title: title,
42
+ ...description === undefined ? {} : {
43
+ description
44
+ },
45
+ table: {
46
+ columns: [
47
+ "Category",
48
+ valueLabel
49
+ ],
50
+ rows: data.map((datum)=>[
51
+ datum.label,
52
+ format(datum.value)
53
+ ])
54
+ },
55
+ className: className,
56
+ children: [
57
+ /*#__PURE__*/ _jsxs("svg", {
58
+ viewBox: `0 0 ${width} ${height}`,
59
+ // Scales to the container's width; the row rhythm is what must stay
60
+ // fixed, and it is expressed in the viewBox.
61
+ className: "h-auto w-full",
62
+ "aria-hidden": true,
63
+ focusable: "false",
64
+ children: [
65
+ ticks.map((tick)=>{
66
+ const x = LABEL_WIDTH + scaleLinear(tick, axisMax, plotWidth);
67
+ return(// Hairline, solid, one step off the surface: present enough to
68
+ // measure against, quiet enough that the bars stay the loud thing.
69
+ /*#__PURE__*/ _jsx("line", {
70
+ x1: x,
71
+ y1: 0,
72
+ x2: x,
73
+ y2: height,
74
+ stroke: "var(--border)",
75
+ strokeWidth: 1
76
+ }, tick));
77
+ }),
78
+ data.map((datum, index)=>{
79
+ const y = index * ROW_HEIGHT + (ROW_HEIGHT - BAR_HEIGHT) / 2;
80
+ const length = scaleLinear(datum.value, axisMax, plotWidth);
81
+ const radius = Math.min(RADIUS, length / 2);
82
+ return /*#__PURE__*/ _jsxs("g", {
83
+ children: [
84
+ /*#__PURE__*/ _jsx("text", {
85
+ x: LABEL_WIDTH - 8,
86
+ y: index * ROW_HEIGHT + ROW_HEIGHT / 2,
87
+ textAnchor: "end",
88
+ dominantBaseline: "middle",
89
+ className: "fill-muted-foreground text-[11px]",
90
+ children: datum.label
91
+ }),
92
+ /*#__PURE__*/ _jsx("path", {
93
+ d: length <= 0 ? "" : `M${LABEL_WIDTH} ${y}` + `H${LABEL_WIDTH + length - radius}` + `a${radius} ${radius} 0 0 1 ${radius} ${radius}` + `V${y + BAR_HEIGHT - radius}` + `a${radius} ${radius} 0 0 1 ${-radius} ${radius}` + `H${LABEL_WIDTH}Z`,
94
+ fill: seriesColor(0)
95
+ }),
96
+ /*#__PURE__*/ _jsx("text", {
97
+ x: LABEL_WIDTH + length + 8,
98
+ y: index * ROW_HEIGHT + ROW_HEIGHT / 2,
99
+ dominantBaseline: "middle",
100
+ className: "fill-foreground text-[11px] tabular-nums",
101
+ children: format(datum.value)
102
+ })
103
+ ]
104
+ }, datum.label);
105
+ })
106
+ ]
107
+ }),
108
+ /*#__PURE__*/ _jsxs("p", {
109
+ className: cn("text-xs text-muted-foreground"),
110
+ children: [
111
+ "Axis to ",
112
+ format(axisMax),
113
+ ", from zero."
114
+ ]
115
+ })
116
+ ]
117
+ });
118
+ }
@@ -0,0 +1,29 @@
1
+ import type { ReactNode } from "react";
2
+ export type BlockCardProps = {
3
+ readonly title: string;
4
+ readonly children: ReactNode;
5
+ readonly className?: string;
6
+ };
7
+ /**
8
+ * The generative-UI block frame: a bordered, square-cornered card with a
9
+ * pulse-dot header. Zero radius is deliberate — it is what separates a
10
+ * generated block from the theme's otherwise-rounded surfaces, so a reader
11
+ * can tell "the agent made this" at a glance. Lifted out of a consumer app
12
+ * unchanged; see `RiskBadge` below for the tone it pairs with inside
13
+ * `children`.
14
+ */
15
+ export declare function BlockCard({ title, children, className }: BlockCardProps): import("react").JSX.Element;
16
+ export type RiskLevel = "low" | "medium" | "high";
17
+ export type RiskBadgeProps = {
18
+ readonly level: RiskLevel;
19
+ readonly label: string;
20
+ readonly note?: string;
21
+ readonly className?: string;
22
+ };
23
+ /**
24
+ * A risk callout for a block whose action carries consequence — approve this
25
+ * order cancellation, run this migration. `level` drives colour only; the
26
+ * `label` is what actually says what the risk is, so the badge is never a
27
+ * bare colour dot.
28
+ */
29
+ export declare function RiskBadge({ level, label, note, className }: RiskBadgeProps): import("react").JSX.Element;
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { TriangleAlert } from "lucide-react";
3
+ import { cn } from "../lib/utils.js";
4
+ /**
5
+ * The generative-UI block frame: a bordered, square-cornered card with a
6
+ * pulse-dot header. Zero radius is deliberate — it is what separates a
7
+ * generated block from the theme's otherwise-rounded surfaces, so a reader
8
+ * can tell "the agent made this" at a glance. Lifted out of a consumer app
9
+ * unchanged; see `RiskBadge` below for the tone it pairs with inside
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
+ });
37
+ }
38
+ const RISK_TONE_CLASS = {
39
+ low: "text-muted-foreground",
40
+ medium: "text-warn",
41
+ high: "text-destructive"
42
+ };
43
+ /**
44
+ * A risk callout for a block whose action carries consequence — approve this
45
+ * order cancellation, run this migration. `level` drives colour only; the
46
+ * `label` is what actually says what the risk is, so the badge is never a
47
+ * 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
+ });
66
+ }
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from "react";
2
+ export type BootScreenProps = {
3
+ /** What the app is doing, in words: "Loading workbench", "Reconnecting…". */
4
+ readonly message: string;
5
+ /** Brand lockup, top left. */
6
+ readonly brand?: ReactNode;
7
+ /** Quiet corner detail — a version string, a build id. */
8
+ readonly footer?: ReactNode;
9
+ readonly className?: string;
10
+ };
11
+ /**
12
+ * The screen before the app: brand top-left, one centered status line, a quiet
13
+ * corner detail. Fills its positioned parent — `BootScreen` is the surface, and
14
+ * whoever mounts it decides whether that is the whole viewport (initial load)
15
+ * or a cover over a live app (`ReconnectingOverlay`).
16
+ *
17
+ * `role="status"` with the message as the accessible name, so a screen reader
18
+ * announces the state change rather than the user waiting on a blank screen.
19
+ * No spinner: the pulsing bar is decorative and `aria-hidden`, and it collapses
20
+ * to a still frame under the theme's reduced-motion rule with nothing to do
21
+ * here.
22
+ */
23
+ export declare function BootScreen({ message, brand, footer, className }: BootScreenProps): import("react").JSX.Element;
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ /**
5
+ * The screen before the app: brand top-left, one centered status line, a quiet
6
+ * corner detail. Fills its positioned parent — `BootScreen` is the surface, and
7
+ * whoever mounts it decides whether that is the whole viewport (initial load)
8
+ * or a cover over a live app (`ReconnectingOverlay`).
9
+ *
10
+ * `role="status"` with the message as the accessible name, so a screen reader
11
+ * announces the state change rather than the user waiting on a blank screen.
12
+ * No spinner: the pulsing bar is decorative and `aria-hidden`, and it collapses
13
+ * to a still frame under the theme's reduced-motion rule with nothing to do
14
+ * here.
15
+ */ export function BootScreen({ message, brand, footer, className }) {
16
+ 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
+ });
49
+ }
@@ -0,0 +1,37 @@
1
+ import type { ReactNode } from "react";
2
+ export type BulkActionBarProps = {
3
+ readonly count: number;
4
+ readonly onClear: () => void;
5
+ /** Action buttons, rendered after the "N selected" label — typically `Button`s. */
6
+ readonly children: ReactNode;
7
+ /** Overrides the default `"Bulk actions"` accessible name outright — for a consumer localizing this published library's one hardcoded English string. */
8
+ readonly label?: string;
9
+ readonly className?: string;
10
+ };
11
+ /**
12
+ * The floating pill that appears once a list has a selection: fixed to the
13
+ * bottom of the viewport (or the nearest ancestor that establishes its own
14
+ * containing block — a `transform`, `filter`, or similar CSS property on an
15
+ * ancestor changes what `fixed` positions against), riding in with a small
16
+ * rise so it reads as newly arrived rather than always having been there.
17
+ * Renders nothing while `count` is 0 — the caller does not need to guard
18
+ * the render site itself.
19
+ *
20
+ * The horizontal centering (`left-1/2` plus a permanent `-translate-x-1/2`)
21
+ * is not part of the entrance animation and is never gated by
22
+ * `motion-safe:` — a `prefers-reduced-motion` viewer gets no animation at
23
+ * all, and if the centering correction lived only in the animation's own
24
+ * `transform`, that viewer would see the bar pinned at the horizontal
25
+ * midpoint with its left edge running off-viewport. The animation itself
26
+ * only touches `opacity`/`translateY`, on an inner element, so it never
27
+ * overwrites the outer element's static centering transform.
28
+ *
29
+ * Escape clears the selection from anywhere on the page while the bar is
30
+ * showing, not only while it has focus — the bar is a global consequence of
31
+ * list state, not a dialog the user has stepped into, so it listens on
32
+ * `window` rather than requiring focus to land on it first. It defers to
33
+ * `event.defaultPrevented`, so a dialog or input stacked above the bar that
34
+ * already handled its own Escape wins instead of also clearing the
35
+ * selection underneath it.
36
+ */
37
+ export declare function BulkActionBar({ count, onClear, children, label, className }: BulkActionBarProps): import("react").JSX.Element | null;
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ /**
5
+ * The floating pill that appears once a list has a selection: fixed to the
6
+ * bottom of the viewport (or the nearest ancestor that establishes its own
7
+ * containing block — a `transform`, `filter`, or similar CSS property on an
8
+ * ancestor changes what `fixed` positions against), riding in with a small
9
+ * rise so it reads as newly arrived rather than always having been there.
10
+ * Renders nothing while `count` is 0 — the caller does not need to guard
11
+ * the render site itself.
12
+ *
13
+ * The horizontal centering (`left-1/2` plus a permanent `-translate-x-1/2`)
14
+ * is not part of the entrance animation and is never gated by
15
+ * `motion-safe:` — a `prefers-reduced-motion` viewer gets no animation at
16
+ * all, and if the centering correction lived only in the animation's own
17
+ * `transform`, that viewer would see the bar pinned at the horizontal
18
+ * midpoint with its left edge running off-viewport. The animation itself
19
+ * only touches `opacity`/`translateY`, on an inner element, so it never
20
+ * overwrites the outer element's static centering transform.
21
+ *
22
+ * Escape clears the selection from anywhere on the page while the bar is
23
+ * showing, not only while it has focus — the bar is a global consequence of
24
+ * list state, not a dialog the user has stepped into, so it listens on
25
+ * `window` rather than requiring focus to land on it first. It defers to
26
+ * `event.defaultPrevented`, so a dialog or input stacked above the bar that
27
+ * already handled its own Escape wins instead of also clearing the
28
+ * selection underneath it.
29
+ */ export function BulkActionBar({ count, onClear, children, label = "Bulk actions", className }) {
30
+ useEffect(()=>{
31
+ if (count === 0) return;
32
+ function onKeyDown(event) {
33
+ if (event.key === "Escape" && !event.defaultPrevented) onClear();
34
+ }
35
+ 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
+ });
64
+ }
@@ -0,0 +1,12 @@
1
+ import { type VariantProps } from "class-variance-authority";
2
+ import type * as React from "react";
3
+ declare const buttonVariantsBase: (props?: ({
4
+ variant?: "link" | "primary" | "secondary" | "outline" | "ghost" | "destructive" | null | undefined;
5
+ size?: "sm" | "md" | "lg" | "icon" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ declare function buttonVariants(props?: VariantProps<typeof buttonVariantsBase>): string;
8
+ export type ButtonProps = React.ComponentProps<"button"> & VariantProps<typeof buttonVariantsBase> & {
9
+ asChild?: boolean;
10
+ };
11
+ export declare function Button({ className, variant, size, asChild, ...props }: ButtonProps): React.JSX.Element;
12
+ export { buttonVariants };
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva } from "class-variance-authority";
4
+ import { twMerge } from "tailwind-merge";
5
+ import { cn } from "../lib/utils.js";
6
+ // The focus ring lives in the theme's base layer, not here — one ring for the
7
+ // whole app, declared once.
8
+ //
9
+ // NOTE FOR THE NEXT IMPLEMENTER: DESIGN.md:377 specifies a white label on the
10
+ // orange primary. That measures 2.69:1, a hard AA failure. `text-primary-
11
+ // foreground` resolves to ink in light (5.53:1) and black in dark (5.34:1),
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
14
+ // rendered fill whatever that fill is, so it needs no per-variant pressed
15
+ // token. Deliberately outside `transition-colors` — a press should land on
16
+ // the frame the pointer goes down, not ease in. The scale feedback gets its
17
+ // own `transition-transform` for the same reason: sharing `transition-colors`
18
+ // would delay the press-down scale behind the color easing.
19
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-colors active:brightness-95 motion-safe:transition-transform motion-safe:duration-100 motion-safe:active:scale-[0.97] disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0", {
20
+ variants: {
21
+ variant: {
22
+ primary: "bg-primary text-primary-foreground hover:bg-primary-active",
23
+ secondary: "bg-secondary text-secondary-foreground hover:opacity-90",
24
+ outline: "border border-input bg-transparent hover:bg-muted",
25
+ ghost: "hover:bg-muted",
26
+ link: "text-primary-emphasis underline-offset-4 hover:underline",
27
+ destructive: "bg-destructive text-destructive-foreground hover:opacity-90"
28
+ },
29
+ size: {
30
+ sm: "h-8 px-3",
31
+ md: "h-9 px-4",
32
+ lg: "h-10 px-6",
33
+ icon: "size-9"
34
+ }
35
+ },
36
+ // link reads as inline text, not a control — it opts out of every size's
37
+ // fixed height/padding rather than getting a box of its own.
38
+ compoundVariants: [
39
+ {
40
+ variant: "link",
41
+ size: [
42
+ "sm",
43
+ "md",
44
+ "lg",
45
+ "icon"
46
+ ],
47
+ class: "h-auto px-0"
48
+ }
49
+ ],
50
+ defaultVariants: {
51
+ variant: "primary",
52
+ size: "md"
53
+ }
54
+ });
55
+ // cva concatenates variant, size, and compound-variant classes as plain
56
+ // strings with no dedup, so the compound override above only wins once
57
+ // tailwind-merge resolves the h-*/px-* conflicts — hence the wrapper instead
58
+ // of exporting buttonVariantsBase directly.
59
+ function buttonVariants(props) {
60
+ return twMerge(buttonVariantsBase(props));
61
+ }
62
+ export function Button({ className, variant, size, asChild = false, ...props }) {
63
+ 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
+ });
72
+ }
73
+ export { buttonVariants };
@@ -0,0 +1,6 @@
1
+ import type * as React from "react";
2
+ export declare function Card({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
3
+ export declare function CardHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
4
+ export declare function CardTitle({ className, ...props }: React.ComponentProps<"h3">): React.JSX.Element;
5
+ export declare function CardDescription({ className, ...props }: React.ComponentProps<"p">): React.JSX.Element;
6
+ export declare function CardFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;