@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
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { Upload } from "lucide-react";
3
4
  import { useRef, useState } from "react";
@@ -18,49 +19,28 @@ import { cn } from "../lib/utils.js";
18
19
  * The input is cleared after each selection so choosing the same file twice
19
20
  * still fires — the browser's change event will not repeat for an identical
20
21
  * value.
21
- */ export function FileInput({ onFiles, label = "Choose files", hint, className, disabled, ...props }) {
22
+ */
23
+ export function FileInput({ onFiles, label = "Choose files", hint, className, disabled, ...props }) {
22
24
  const [dragging, setDragging] = useState(false);
23
25
  const inputRef = useRef(null);
24
- return /*#__PURE__*/ _jsxs("label", {
25
- onDragOver: (event)=>{
26
- if (disabled === true) return;
26
+ return (_jsxs("label", { onDragOver: (event) => {
27
+ if (disabled === true)
28
+ return;
27
29
  event.preventDefault();
28
30
  setDragging(true);
29
- },
30
- onDragLeave: ()=>setDragging(false),
31
- onDrop: (event)=>{
32
- if (disabled === true) return;
31
+ }, onDragLeave: () => setDragging(false), onDrop: (event) => {
32
+ if (disabled === true)
33
+ return;
33
34
  event.preventDefault();
34
35
  setDragging(false);
35
- if (event.dataTransfer.files.length > 0) onFiles(event.dataTransfer.files);
36
- },
37
- className: cn("flex cursor-pointer flex-col items-center gap-1.5 rounded-lg border border-dashed border-input px-6 py-8 text-center transition-colors", dragging && "border-primary-emphasis bg-primary/10", disabled === true ? "cursor-not-allowed opacity-50" : "hover:bg-muted", // The focus ring lives on the hidden input; project it onto the zone,
36
+ if (event.dataTransfer.files.length > 0)
37
+ onFiles(event.dataTransfer.files);
38
+ }, className: cn("flex cursor-pointer flex-col items-center gap-1.5 rounded-lg border border-dashed border-input px-6 py-8 text-center transition-colors", dragging && "border-primary-emphasis bg-primary/10", disabled === true ? "cursor-not-allowed opacity-50" : "hover:bg-muted",
39
+ // The focus ring lives on the hidden input; project it onto the zone,
38
40
  // which is the thing the user can actually see.
39
- "has-[input:focus-visible]:outline has-[input:focus-visible]:outline-2 has-[input:focus-visible]:outline-offset-2 has-[input:focus-visible]:outline-[var(--ring)]", className),
40
- children: [
41
- /*#__PURE__*/ _jsx("input", {
42
- ref: inputRef,
43
- type: "file",
44
- disabled: disabled,
45
- className: "sr-only",
46
- onChange: (event)=>{
47
- if (event.target.files !== null && event.target.files.length > 0) onFiles(event.target.files);
41
+ "has-[input:focus-visible]:outline has-[input:focus-visible]:outline-2 has-[input:focus-visible]:outline-offset-2 has-[input:focus-visible]:outline-[var(--ring)]", className), children: [_jsx("input", { ref: inputRef, type: "file", disabled: disabled, className: "sr-only", onChange: (event) => {
42
+ if (event.target.files !== null && event.target.files.length > 0)
43
+ onFiles(event.target.files);
48
44
  event.target.value = "";
49
- },
50
- ...props
51
- }),
52
- /*#__PURE__*/ _jsx(Upload, {
53
- className: "size-5 text-muted-foreground",
54
- "aria-hidden": true
55
- }),
56
- /*#__PURE__*/ _jsx("span", {
57
- className: "text-sm font-medium",
58
- children: label
59
- }),
60
- /*#__PURE__*/ _jsx("span", {
61
- className: "text-xs text-muted-foreground",
62
- children: hint ?? "or drag them here"
63
- })
64
- ]
65
- });
45
+ }, ...props }), _jsx(Upload, { className: "size-5 text-muted-foreground", "aria-hidden": true }), _jsx("span", { className: "text-sm font-medium", children: label }), _jsx("span", { className: "text-xs text-muted-foreground", children: hint ?? "or drag them here" })] }));
66
46
  }
@@ -39,4 +39,4 @@ export type FilterBarProps = {
39
39
  * URL. Owning it here would mean every consumer fights the component to make
40
40
  * their filters linkable.
41
41
  */
42
- export declare function FilterBar({ filters, onChange, children, className }: FilterBarProps): import("react").JSX.Element;
42
+ export declare function FilterBar({ filters, onChange, children, className, }: FilterBarProps): 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 { X } from "lucide-react";
3
4
  import { cn } from "../lib/utils.js";
@@ -21,75 +22,14 @@ import { Button } from "./button.js";
21
22
  * Filter state lives with the caller because it almost always also lives in the
22
23
  * URL. Owning it here would mean every consumer fights the component to make
23
24
  * their filters linkable.
24
- */ export function FilterBar({ filters, onChange, children, className }) {
25
- const active = filters.filter((filter)=>filter.value !== null);
26
- return /*#__PURE__*/ _jsxs("div", {
27
- className: cn("flex flex-col gap-2", className),
28
- children: [
29
- /*#__PURE__*/ _jsxs("div", {
30
- className: "flex flex-wrap items-center gap-3",
31
- children: [
32
- filters.map((filter)=>/*#__PURE__*/ _jsxs("label", {
33
- className: "flex items-center gap-1.5 text-xs text-muted-foreground",
34
- children: [
35
- filter.label,
36
- /*#__PURE__*/ _jsxs("select", {
37
- value: filter.value ?? "",
38
- onChange: (event)=>onChange(filter.id, event.target.value === "" ? null : event.target.value),
39
- className: "h-8 rounded-md border border-input bg-card px-2 text-xs text-foreground",
40
- children: [
41
- /*#__PURE__*/ _jsx("option", {
42
- value: "",
43
- children: filter.anyLabel
44
- }),
45
- filter.options.map((option)=>/*#__PURE__*/ _jsx("option", {
46
- value: option.value,
47
- children: option.label
48
- }, option.value))
49
- ]
50
- })
51
- ]
52
- }, filter.id)),
53
- children
54
- ]
55
- }),
56
- active.length === 0 ? null : /*#__PURE__*/ _jsxs("div", {
57
- className: "flex flex-wrap items-center gap-2",
58
- children: [
59
- active.map((filter)=>{
60
- const option = filter.options.find((candidate)=>candidate.value === filter.value);
61
- return /*#__PURE__*/ _jsxs("button", {
62
- type: "button",
63
- onClick: ()=>onChange(filter.id, null),
64
- // The whole chip is the remove control, and its accessible name
65
- // says so — an "×" alone is announced as "times".
66
- "aria-label": `Remove filter ${filter.label}: ${option?.label ?? filter.value}`,
67
- className: "inline-flex items-center gap-1 rounded-sm bg-muted px-2 py-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground",
68
- children: [
69
- /*#__PURE__*/ _jsx("span", {
70
- className: "font-medium text-foreground",
71
- children: filter.label
72
- }),
73
- option?.label ?? filter.value,
74
- /*#__PURE__*/ _jsx(X, {
75
- className: "size-3",
76
- "aria-hidden": true
77
- })
78
- ]
79
- }, filter.id);
80
- }),
81
- /*#__PURE__*/ _jsx(Button, {
82
- type: "button",
83
- variant: "ghost",
84
- size: "sm",
85
- className: "h-6 px-2 text-xs",
86
- onClick: ()=>{
87
- for (const filter of active)onChange(filter.id, null);
88
- },
89
- children: "Clear all"
90
- })
91
- ]
92
- })
93
- ]
94
- });
25
+ */
26
+ export function FilterBar({ filters, onChange, children, className, }) {
27
+ const active = filters.filter((filter) => filter.value !== null);
28
+ return (_jsxs("div", { className: cn("flex flex-col gap-2", className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [filters.map((filter) => (_jsxs("label", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [filter.label, _jsxs("select", { value: filter.value ?? "", onChange: (event) => onChange(filter.id, event.target.value === "" ? null : event.target.value), className: "h-8 rounded-md border border-input bg-card px-2 text-xs text-foreground", children: [_jsx("option", { value: "", children: filter.anyLabel }), filter.options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value)))] })] }, filter.id))), children] }), active.length === 0 ? null : (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [active.map((filter) => {
29
+ const option = filter.options.find((candidate) => candidate.value === filter.value);
30
+ return (_jsxs("button", { type: "button", onClick: () => onChange(filter.id, null), "aria-label": `Remove filter ${filter.label}: ${option?.label ?? filter.value}`, className: "inline-flex items-center gap-1 rounded-sm bg-muted px-2 py-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground", children: [_jsx("span", { className: "font-medium text-foreground", children: filter.label }), option?.label ?? filter.value, _jsx(X, { className: "size-3", "aria-hidden": true })] }, filter.id));
31
+ }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-6 px-2 text-xs", onClick: () => {
32
+ for (const filter of active)
33
+ onChange(filter.id, null);
34
+ }, children: "Clear all" })] }))] }));
95
35
  }
@@ -11,4 +11,4 @@ export type FilterChipProps = {
11
11
  * `<button>` with `aria-pressed`, not a styled label, so the selection state
12
12
  * is announced and the control is reachable with Space/Enter alone.
13
13
  */
14
- export declare function FilterChip({ selected, onClick, children, count, className }: FilterChipProps): import("react").JSX.Element;
14
+ export declare function FilterChip({ selected, onClick, children, count, className, }: FilterChipProps): import("react").JSX.Element;
@@ -4,20 +4,12 @@ import { cn } from "../lib/utils.js";
4
4
  * A toggleable filter pill — a category, a tag, a facet value. A real
5
5
  * `<button>` with `aria-pressed`, not a styled label, so the selection state
6
6
  * is announced and the control is reachable with Space/Enter alone.
7
- */ export function FilterChip({ selected = false, onClick, children, count, className }) {
8
- return /*#__PURE__*/ _jsxs("button", {
9
- type: "button",
10
- "aria-pressed": selected,
11
- onClick: onClick,
12
- className: cn(// active:brightness-95 mirrors Button's press state: it lands on
7
+ */
8
+ export function FilterChip({ selected = false, onClick, children, count, className, }) {
9
+ return (_jsxs("button", { type: "button", "aria-pressed": selected, onClick: onClick, className: cn(
10
+ // active:brightness-95 mirrors Button's press state: it lands on
13
11
  // pointer-down, so it sits outside transition-colors.
14
- "inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-semibold transition-colors ease-out active:brightness-95", selected ? "border-border bg-card text-foreground shadow-sm" : "border-border bg-transparent text-muted-foreground hover:bg-muted hover:text-foreground", className),
15
- children: [
16
- children,
17
- count === undefined ? null : /*#__PURE__*/ _jsx("span", {
18
- className: cn("text-[10.5px] font-bold", selected ? "text-primary-emphasis" : "text-muted-foreground"),
19
- children: count
20
- })
21
- ]
22
- });
12
+ "inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-semibold transition-colors ease-out active:brightness-95", selected
13
+ ? "border-border bg-card text-foreground shadow-sm"
14
+ : "border-border bg-transparent text-muted-foreground hover:bg-muted hover:text-foreground", className), children: [children, count === undefined ? null : (_jsx("span", { className: cn("text-[10.5px] font-bold", selected ? "text-primary-emphasis" : "text-muted-foreground"), children: count }))] }));
23
15
  }
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import { type GateShellModel } from "../lib/workflow-registry.js";
3
+ export type { GateKind, GateShellModel } from "../lib/workflow-registry.js";
3
4
  export type GateBlockProps = {
4
5
  readonly gate: GateShellModel;
5
6
  /** The interactive payload — a review list, choice buttons, a form. */
@@ -13,4 +14,4 @@ export type GateBlockProps = {
13
14
  * component only frames it, so the resume-payload contract stays wherever
14
15
  * the host's signal-sending logic already lives.
15
16
  */
16
- export declare function GateBlock({ gate, children, footer, className }: GateBlockProps): import("react").JSX.Element;
17
+ export declare function GateBlock({ gate, children, footer, className, }: GateBlockProps): import("react").JSX.Element;
@@ -1,37 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { GATE_KIND_LABEL } from "../lib/workflow-registry.js";
2
+ import { GATE_KIND_LABEL, } from "../lib/workflow-registry.js";
3
3
  import { cn } from "../lib/utils.js";
4
4
  /**
5
5
  * Presentational chrome for a pending gate: a run parked on a human
6
6
  * decision. The interactive payload is entirely the caller's — this
7
7
  * component only frames it, so the resume-payload contract stays wherever
8
8
  * the host's signal-sending logic already lives.
9
- */ export function GateBlock({ gate, children, footer, className }) {
10
- return /*#__PURE__*/ _jsxs("section", {
11
- "data-gate-kind": gate.kind,
12
- "aria-label": GATE_KIND_LABEL[gate.kind],
13
- className: cn("rounded-lg border border-primary-emphasis/30 bg-primary/5 px-3.5 py-3", className),
14
- children: [
15
- /*#__PURE__*/ _jsx("p", {
16
- className: "text-[10.5px] font-bold uppercase tracking-[0.05em] text-primary-emphasis",
17
- children: GATE_KIND_LABEL[gate.kind]
18
- }),
19
- /*#__PURE__*/ _jsx("h3", {
20
- className: "mt-1 text-sm font-semibold",
21
- children: gate.title
22
- }),
23
- gate.prompt === undefined ? null : /*#__PURE__*/ _jsx("p", {
24
- className: "mt-1 text-xs leading-snug text-muted-foreground",
25
- children: gate.prompt
26
- }),
27
- children === undefined ? null : /*#__PURE__*/ _jsx("div", {
28
- className: "mt-3",
29
- children: children
30
- }),
31
- footer === undefined ? null : /*#__PURE__*/ _jsx("div", {
32
- className: "mt-3 flex flex-wrap items-center gap-2",
33
- children: footer
34
- })
35
- ]
36
- });
9
+ */
10
+ export function GateBlock({ gate, children, footer, className, }) {
11
+ return (_jsxs("section", { "data-gate-kind": gate.kind, "aria-label": GATE_KIND_LABEL[gate.kind], className: cn("rounded-lg border border-primary-emphasis/30 bg-primary/5 px-3.5 py-3", className), children: [_jsx("p", { className: "text-[10.5px] font-bold uppercase tracking-[0.05em] text-primary-emphasis", children: GATE_KIND_LABEL[gate.kind] }), _jsx("h3", { className: "mt-1 text-sm font-semibold", children: gate.title }), gate.prompt === undefined ? null : (_jsx("p", { className: "mt-1 text-xs leading-snug text-muted-foreground", children: gate.prompt })), children === undefined ? null : _jsx("div", { className: "mt-3", children: children }), footer === undefined ? null : (_jsx("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: footer }))] }));
37
12
  }
@@ -10,4 +10,4 @@ export type HorizontalStepperProps = {
10
10
  * change, so a run with more steps than fit on screen never leaves the
11
11
  * active one off to the side unannounced.
12
12
  */
13
- export declare function HorizontalStepper({ steps, className }: HorizontalStepperProps): import("react").JSX.Element;
13
+ export declare function HorizontalStepper({ steps, className, }: HorizontalStepperProps): import("react").JSX.Element;
@@ -1,6 +1,7 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useScrollCurrentIntoView } from "../hooks/use-scroll-current-into-view.js";
3
- import { workflowStepGlyph, workflowStepLabelClass } from "../lib/workflow-run-progress.js";
4
+ import { workflowStepGlyph, workflowStepLabelClass, } from "../lib/workflow-run-progress.js";
4
5
  import { cn } from "../lib/utils.js";
5
6
  // Above this many steps, an even split can't give every label readable room,
6
7
  // so labels compress to numbers-only pills except for the current step — the
@@ -8,9 +9,12 @@ import { cn } from "../lib/utils.js";
8
9
  // renders (`sr-only`) so a screen reader still hears the full sequence.
9
10
  const LABEL_VISIBLE_STEP_THRESHOLD = 5;
10
11
  function pillClass(status) {
11
- if (status === "completed") return "bg-success text-success-foreground";
12
- if (status === "failed") return "bg-destructive text-destructive-foreground";
13
- if (status === "current") return "bg-primary text-primary-foreground";
12
+ if (status === "completed")
13
+ return "bg-success text-success-foreground";
14
+ if (status === "failed")
15
+ return "bg-destructive text-destructive-foreground";
16
+ if (status === "current")
17
+ return "bg-primary text-primary-foreground";
14
18
  return "bg-muted text-muted-foreground";
15
19
  }
16
20
  /**
@@ -19,47 +23,16 @@ function pillClass(status) {
19
23
  * work. Scrolls the current step into view on mount and on every step
20
24
  * change, so a run with more steps than fit on screen never leaves the
21
25
  * active one off to the side unannounced.
22
- */ export function HorizontalStepper({ steps, className }) {
23
- const currentStep = steps.find((step)=>step.status === "current");
26
+ */
27
+ export function HorizontalStepper({ steps, className, }) {
28
+ const currentStep = steps.find((step) => step.status === "current");
24
29
  const currentRef = useScrollCurrentIntoView(currentStep?.number ?? -1);
25
30
  const compress = steps.length > LABEL_VISIBLE_STEP_THRESHOLD;
26
- return /*#__PURE__*/ _jsx("div", {
27
- className: cn("border-b border-border bg-card px-6 py-5", className),
28
- children: /*#__PURE__*/ _jsx("ol", {
29
- "aria-label": "Workflow progress",
30
- className: "flex items-center gap-2 overflow-x-auto [mask-image:linear-gradient(to_right,transparent,black_12px,black_calc(100%-12px),transparent)] md:gap-3",
31
- children: steps.map((step, index)=>/*#__PURE__*/ _jsxs("li", {
32
- ref: step.status === "current" ? currentRef : undefined,
33
- "aria-current": step.status === "current" ? "step" : undefined,
34
- className: cn("flex min-w-0 items-center gap-2 last:flex-initial md:gap-3", compress ? step.status === "current" ? "flex-[8_1_0%]" : "flex-1" : "flex-1"),
35
- children: [
36
- /*#__PURE__*/ _jsxs("span", {
37
- className: "relative flex size-8 shrink-0 items-center justify-center",
38
- children: [
39
- step.status === "current" ? /*#__PURE__*/ _jsx("span", {
40
- "aria-hidden": true,
41
- className: "absolute inset-0 rounded-full bg-primary/30 motion-safe:[animation:corbits-status-pulse_1.8s_ease-out_infinite]"
42
- }) : null,
43
- /*#__PURE__*/ _jsx("span", {
44
- className: cn("relative flex size-8 items-center justify-center rounded-full text-sm font-medium transition-colors", pillClass(step.status)),
45
- children: workflowStepGlyph(step.status, step.number)
46
- })
47
- ]
48
- }),
49
- /*#__PURE__*/ _jsx("span", {
50
- title: step.label,
51
- className: cn("min-w-0 flex-1 truncate text-sm font-medium", compress && step.status !== "current" ? "sr-only" : workflowStepLabelClass(step.status)),
52
- children: step.label
53
- }),
54
- index === steps.length - 1 ? null : /*#__PURE__*/ _jsx("span", {
55
- className: cn("h-0.5 shrink-0 overflow-hidden rounded-full bg-border", compress ? "min-w-2 flex-1" : "w-4 md:w-6"),
56
- children: /*#__PURE__*/ _jsx("span", {
57
- "data-filled": step.status === "completed",
58
- className: "block h-full w-full origin-left rounded-full bg-success transition-transform duration-300 ease-out data-[filled=false]:scale-x-0 data-[filled=true]:scale-x-100"
59
- })
60
- })
61
- ]
62
- }, step.number))
63
- })
64
- });
31
+ return (_jsx("div", { className: cn("border-b border-border bg-card px-6 py-5", className), children: _jsx("ol", { "aria-label": "Workflow progress", className: "flex items-center gap-2 overflow-x-auto [mask-image:linear-gradient(to_right,transparent,black_12px,black_calc(100%-12px),transparent)] md:gap-3", children: steps.map((step, index) => (_jsxs("li", { ref: step.status === "current" ? currentRef : undefined, "aria-current": step.status === "current" ? "step" : undefined, className: cn("flex min-w-0 items-center gap-2 last:flex-initial md:gap-3", compress
32
+ ? step.status === "current"
33
+ ? "flex-[8_1_0%]"
34
+ : "flex-1"
35
+ : "flex-1"), children: [_jsxs("span", { className: "relative flex size-8 shrink-0 items-center justify-center", children: [step.status === "current" ? (_jsx("span", { "aria-hidden": true, className: "absolute inset-0 rounded-full bg-primary/30 motion-safe:[animation:corbits-status-pulse_1.8s_ease-out_infinite]" })) : null, _jsx("span", { className: cn("relative flex size-8 items-center justify-center rounded-full text-sm font-medium transition-colors", pillClass(step.status)), children: workflowStepGlyph(step.status, step.number) })] }), _jsx("span", { title: step.label, className: cn("min-w-0 flex-1 truncate text-sm font-medium", compress && step.status !== "current"
36
+ ? "sr-only"
37
+ : workflowStepLabelClass(step.status)), children: step.label }), index === steps.length - 1 ? null : (_jsx("span", { className: cn("h-0.5 shrink-0 overflow-hidden rounded-full bg-border", compress ? "min-w-2 flex-1" : "w-4 md:w-6"), children: _jsx("span", { "data-filled": step.status === "completed", className: "block h-full w-full origin-left rounded-full bg-success transition-transform duration-300 ease-out data-[filled=false]:scale-x-0 data-[filled=true]:scale-x-100" }) }))] }, step.number))) }) }));
65
38
  }
package/dist/ui/input.js CHANGED
@@ -5,10 +5,5 @@ import { cn } from "../lib/utils.js";
5
5
  // edge. `border-border` is the soft decorative one and must not be used here.
6
6
  // The focus ring comes from the theme's base layer, not from this file.
7
7
  export function Input({ className, type, ...props }) {
8
- return /*#__PURE__*/ _jsx("input", {
9
- type: type,
10
- "data-slot": "input",
11
- className: cn("flex h-9 w-full min-w-0 rounded-md border border-input bg-card px-3 py-1 text-sm shadow-xs transition-colors", "placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground", "aria-invalid:border-destructive disabled:cursor-not-allowed disabled:opacity-50", className),
12
- ...props
13
- });
8
+ return (_jsx("input", { type: type, "data-slot": "input", className: cn("flex h-9 w-full min-w-0 rounded-md border border-input bg-card px-3 py-1 text-sm shadow-xs transition-colors", "placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground", "aria-invalid:border-destructive disabled:cursor-not-allowed disabled:opacity-50", className), ...props }));
14
9
  }
@@ -7,7 +7,7 @@ export type InspectorEmptyProps = {
7
7
  /** The "nothing selected" message inside an inspector rail. Deliberately not
8
8
  * `EmptyState` — that component centres and pads for a full-width surface;
9
9
  * an inspector's empty message sits left-aligned in a narrow side panel. */
10
- export declare function InspectorEmpty({ title, description, className }: InspectorEmptyProps): import("react").JSX.Element;
10
+ export declare function InspectorEmpty({ title, description, className, }: InspectorEmptyProps): import("react").JSX.Element;
11
11
  export type InspectorHeaderProps = {
12
12
  readonly eyebrow?: ReactNode;
13
13
  readonly title: ReactNode;
@@ -16,8 +16,8 @@ export type InspectorHeaderProps = {
16
16
  readonly className?: string;
17
17
  };
18
18
  /** The chip row, title and action buttons at the top of an inspector. */
19
- export declare function InspectorHeader({ eyebrow, title, description, actions, className }: InspectorHeaderProps): import("react").JSX.Element;
20
- export declare function InspectorPanelTitle({ children, className }: {
19
+ export declare function InspectorHeader({ eyebrow, title, description, actions, className, }: InspectorHeaderProps): import("react").JSX.Element;
20
+ export declare function InspectorPanelTitle({ children, className, }: {
21
21
  readonly children: ReactNode;
22
22
  readonly className?: string;
23
23
  }): import("react").JSX.Element;
@@ -26,7 +26,7 @@ export type InspectorKvRow = {
26
26
  readonly value: ReactNode;
27
27
  readonly mono?: boolean;
28
28
  };
29
- export declare function InspectorKv({ rows, className }: {
29
+ export declare function InspectorKv({ rows, className, }: {
30
30
  readonly rows: readonly InspectorKvRow[];
31
31
  readonly className?: string;
32
32
  }): import("react").JSX.Element;
@@ -44,4 +44,4 @@ export type InspectorShellProps = {
44
44
  * separately so a caller can compose its own layout inside this shell
45
45
  * instead of going through a single big inspector component.
46
46
  */
47
- export declare function InspectorShell({ header, children, empty, className }: InspectorShellProps): import("react").JSX.Element;
47
+ export declare function InspectorShell({ header, children, empty, className, }: InspectorShellProps): import("react").JSX.Element;
@@ -2,67 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/utils.js";
3
3
  /** The "nothing selected" message inside an inspector rail. Deliberately not
4
4
  * `EmptyState` — that component centres and pads for a full-width surface;
5
- * an inspector's empty message sits left-aligned in a narrow side panel. */ export function InspectorEmpty({ title, description, className }) {
6
- return /*#__PURE__*/ _jsxs("div", {
7
- className: cn("max-w-64", className),
8
- children: [
9
- /*#__PURE__*/ _jsx("p", {
10
- className: "text-sm font-semibold",
11
- children: title
12
- }),
13
- description === undefined ? null : /*#__PURE__*/ _jsx("p", {
14
- className: "mt-1.5 text-xs leading-snug text-muted-foreground",
15
- children: description
16
- })
17
- ]
18
- });
5
+ * an inspector's empty message sits left-aligned in a narrow side panel. */
6
+ export function InspectorEmpty({ title, description, className, }) {
7
+ return (_jsxs("div", { className: cn("max-w-64", className), children: [_jsx("p", { className: "text-sm font-semibold", children: title }), description === undefined ? null : (_jsx("p", { className: "mt-1.5 text-xs leading-snug text-muted-foreground", children: description }))] }));
19
8
  }
20
- /** The chip row, title and action buttons at the top of an inspector. */ export function InspectorHeader({ eyebrow, title, description, actions, className }) {
21
- return /*#__PURE__*/ _jsxs("div", {
22
- className: cn("flex flex-col gap-2", className),
23
- children: [
24
- eyebrow === undefined ? null : /*#__PURE__*/ _jsx("div", {
25
- className: "flex flex-wrap items-center gap-1.5",
26
- children: eyebrow
27
- }),
28
- /*#__PURE__*/ _jsx("h2", {
29
- className: "text-base font-bold tracking-tight",
30
- children: title
31
- }),
32
- description === undefined ? null : /*#__PURE__*/ _jsx("p", {
33
- className: "text-xs leading-snug text-muted-foreground",
34
- children: description
35
- }),
36
- actions === undefined ? null : /*#__PURE__*/ _jsx("div", {
37
- className: "mt-1 flex flex-wrap items-center gap-1.5",
38
- children: actions
39
- })
40
- ]
41
- });
9
+ /** The chip row, title and action buttons at the top of an inspector. */
10
+ export function InspectorHeader({ eyebrow, title, description, actions, className, }) {
11
+ return (_jsxs("div", { className: cn("flex flex-col gap-2", className), children: [eyebrow === undefined ? null : (_jsx("div", { className: "flex flex-wrap items-center gap-1.5", children: eyebrow })), _jsx("h2", { className: "text-base font-bold tracking-tight", children: title }), description === undefined ? null : (_jsx("p", { className: "text-xs leading-snug text-muted-foreground", children: description })), actions === undefined ? null : (_jsx("div", { className: "mt-1 flex flex-wrap items-center gap-1.5", children: actions }))] }));
42
12
  }
43
- export function InspectorPanelTitle({ children, className }) {
44
- return /*#__PURE__*/ _jsx("div", {
45
- className: cn("mb-2 mt-4 text-[10.5px] font-bold uppercase tracking-[0.05em] text-muted-foreground first:mt-0", className),
46
- children: children
47
- });
13
+ export function InspectorPanelTitle({ children, className, }) {
14
+ return (_jsx("div", { className: cn("mb-2 mt-4 text-[10.5px] font-bold uppercase tracking-[0.05em] text-muted-foreground first:mt-0", className), children: children }));
48
15
  }
49
- export function InspectorKv({ rows, className }) {
50
- return /*#__PURE__*/ _jsx("div", {
51
- className: cn("flex flex-col gap-1.5", className),
52
- children: rows.map((row)=>/*#__PURE__*/ _jsxs("div", {
53
- className: "flex items-baseline justify-between gap-3 text-xs",
54
- children: [
55
- /*#__PURE__*/ _jsx("span", {
56
- className: "shrink-0 text-muted-foreground",
57
- children: row.label
58
- }),
59
- /*#__PURE__*/ _jsx("span", {
60
- className: cn("min-w-0 truncate text-right", row.mono === true && "font-mono"),
61
- children: row.value
62
- })
63
- ]
64
- }, row.label))
65
- });
16
+ export function InspectorKv({ rows, className, }) {
17
+ return (_jsx("div", { className: cn("flex flex-col gap-1.5", className), children: rows.map((row) => (_jsxs("div", { className: "flex items-baseline justify-between gap-3 text-xs", children: [_jsx("span", { className: "shrink-0 text-muted-foreground", children: row.label }), _jsx("span", { className: cn("min-w-0 truncate text-right", row.mono === true && "font-mono"), children: row.value })] }, row.label))) }));
66
18
  }
67
19
  /**
68
20
  * The side-rail frame every inspector shares: a header region, a scrollable
@@ -70,29 +22,10 @@ export function InspectorKv({ rows, className }) {
70
22
  * `InspectorHeader`/`InspectorKv`/`InspectorPanelTitle` are exported
71
23
  * separately so a caller can compose its own layout inside this shell
72
24
  * instead of going through a single big inspector component.
73
- */ export function InspectorShell({ header, children, empty, className }) {
25
+ */
26
+ export function InspectorShell({ header, children, empty, className, }) {
74
27
  if (empty !== undefined && header === undefined) {
75
- return /*#__PURE__*/ _jsx("aside", {
76
- "aria-label": "Inspector",
77
- className: cn("flex min-h-0 flex-col overflow-auto border-l border-border bg-card", className),
78
- children: /*#__PURE__*/ _jsx("div", {
79
- className: "flex flex-1 flex-col items-start justify-center px-5 py-10",
80
- children: empty
81
- })
82
- });
28
+ return (_jsx("aside", { "aria-label": "Inspector", className: cn("flex min-h-0 flex-col overflow-auto border-l border-border bg-card", className), children: _jsx("div", { className: "flex flex-1 flex-col items-start justify-center px-5 py-10", children: empty }) }));
83
29
  }
84
- return /*#__PURE__*/ _jsxs("aside", {
85
- "aria-label": "Inspector",
86
- className: cn("flex min-h-0 flex-col overflow-hidden border-l border-border bg-card", className),
87
- children: [
88
- header === undefined ? null : /*#__PURE__*/ _jsx("div", {
89
- className: "shrink-0 border-b border-border px-4 pb-3 pt-4",
90
- children: header
91
- }),
92
- /*#__PURE__*/ _jsx("div", {
93
- className: "min-h-0 flex-1 overflow-auto px-4 py-3",
94
- children: children
95
- })
96
- ]
97
- });
30
+ return (_jsxs("aside", { "aria-label": "Inspector", className: cn("flex min-h-0 flex-col overflow-hidden border-l border-border bg-card", className), children: [header === undefined ? null : (_jsx("div", { className: "shrink-0 border-b border-border px-4 pb-3 pt-4", children: header })), _jsx("div", { className: "min-h-0 flex-1 overflow-auto px-4 py-3", children: children })] }));
98
31
  }
@@ -36,4 +36,4 @@ export declare function intakeFieldsComplete(fields: readonly IntakeField[], val
36
36
  * host owns the values, so the same form backs a one-off run and a saved
37
37
  * schedule without this file knowing which.
38
38
  */
39
- export declare function IntakeForm({ fields, values, onChange, idPrefix, disabled, className }: IntakeFormProps): import("react").JSX.Element | null;
39
+ export declare function IntakeForm({ fields, values, onChange, idPrefix, disabled, className, }: IntakeFormProps): import("react").JSX.Element | null;