@corbits/react-ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +174 -499
  2. package/README.md +228 -85
  3. package/dist/blocks/login/auth-layout.d.ts +1 -1
  4. package/dist/blocks/login/auth-layout.js +3 -33
  5. package/dist/blocks/login/login-form.js +6 -119
  6. package/dist/hooks/use-command-palette-navigation.js +18 -17
  7. package/dist/hooks/use-controllable-state.d.ts +2 -2
  8. package/dist/hooks/use-controllable-state.js +23 -15
  9. package/dist/hooks/use-delayed-autofocus.js +10 -11
  10. package/dist/hooks/use-dismissable-popover.d.ts +2 -2
  11. package/dist/hooks/use-dismissable-popover.js +21 -29
  12. package/dist/hooks/use-list-selection.js +54 -85
  13. package/dist/hooks/use-prefers-reduced-motion.js +8 -4
  14. package/dist/hooks/use-scroll-current-into-view.js +5 -7
  15. package/dist/index.d.ts +0 -11
  16. package/dist/index.js +10 -19
  17. package/dist/lib/artifact.js +16 -35
  18. package/dist/lib/chart-geometry.js +33 -20
  19. package/dist/lib/chart-palette.js +17 -31
  20. package/dist/lib/chat-message.js +32 -13
  21. package/dist/lib/chat-parts.js +2 -1
  22. package/dist/lib/csv.js +42 -26
  23. package/dist/lib/metrics.js +30 -48
  24. package/dist/lib/now-item.js +26 -25
  25. package/dist/lib/relative-time.js +14 -29
  26. package/dist/lib/theme.js +32 -30
  27. package/dist/lib/url.js +9 -8
  28. package/dist/lib/workflow-display-flow.js +37 -33
  29. package/dist/lib/workflow-registry.d.ts +0 -41
  30. package/dist/lib/workflow-registry.js +13 -23
  31. package/dist/lib/workflow-run-error.js +16 -20
  32. package/dist/lib/workflow-run-progress.js +94 -52
  33. package/dist/lib/workflow-run.js +17 -13
  34. package/dist/styles.css +11 -11
  35. package/dist/test/render-hook.js +11 -12
  36. package/dist/theme.css +51 -14
  37. package/dist/ui/agent-turn.d.ts +1 -1
  38. package/dist/ui/agent-turn.js +4 -37
  39. package/dist/ui/animated-number.js +15 -28
  40. package/dist/ui/approval-card.js +5 -90
  41. package/dist/ui/artifact-body.js +47 -125
  42. package/dist/ui/artifact-notice.d.ts +1 -1
  43. package/dist/ui/artifact-notice.js +9 -16
  44. package/dist/ui/avatar.d.ts +1 -1
  45. package/dist/ui/avatar.js +11 -48
  46. package/dist/ui/badge.js +4 -12
  47. package/dist/ui/bar-chart.d.ts +1 -1
  48. package/dist/ui/bar-chart.js +22 -74
  49. package/dist/ui/block-card.js +7 -45
  50. package/dist/ui/boot-screen.d.ts +1 -1
  51. package/dist/ui/boot-screen.js +4 -33
  52. package/dist/ui/bulk-action-bar.d.ts +1 -1
  53. package/dist/ui/bulk-action-bar.js +14 -33
  54. package/dist/ui/button.js +10 -24
  55. package/dist/ui/card.js +5 -25
  56. package/dist/ui/category-bars.js +14 -59
  57. package/dist/ui/chart-frame.d.ts +2 -2
  58. package/dist/ui/chart-frame.js +6 -85
  59. package/dist/ui/chat-composer.js +4 -16
  60. package/dist/ui/chat-dock-timing.js +7 -3
  61. package/dist/ui/chat-input.js +20 -100
  62. package/dist/ui/chat-panel.d.ts +1 -1
  63. package/dist/ui/chat-panel.js +7 -41
  64. package/dist/ui/chat-thread.js +13 -31
  65. package/dist/ui/checkbox.js +10 -52
  66. package/dist/ui/command-palette.js +71 -246
  67. package/dist/ui/compare-body.d.ts +1 -1
  68. package/dist/ui/compare-body.js +28 -98
  69. package/dist/ui/confirm-button.js +8 -15
  70. package/dist/ui/corbits-mark.js +7 -16
  71. package/dist/ui/csv-table.d.ts +1 -1
  72. package/dist/ui/csv-table.js +8 -50
  73. package/dist/ui/dialog.d.ts +1 -1
  74. package/dist/ui/dialog.js +32 -62
  75. package/dist/ui/dictation-status-line.js +7 -25
  76. package/dist/ui/dither-canvas.d.ts +1 -1
  77. package/dist/ui/dither-canvas.js +31 -56
  78. package/dist/ui/embed-body.d.ts +1 -1
  79. package/dist/ui/embed-body.js +7 -56
  80. package/dist/ui/empty-state.d.ts +1 -1
  81. package/dist/ui/empty-state.js +3 -26
  82. package/dist/ui/file-input.js +17 -37
  83. package/dist/ui/filter-bar.d.ts +1 -1
  84. package/dist/ui/filter-bar.js +11 -71
  85. package/dist/ui/filter-chip.d.ts +1 -1
  86. package/dist/ui/filter-chip.js +7 -15
  87. package/dist/ui/gate-block.d.ts +2 -1
  88. package/dist/ui/gate-block.js +4 -29
  89. package/dist/ui/horizontal-stepper.d.ts +1 -1
  90. package/dist/ui/horizontal-stepper.js +18 -45
  91. package/dist/ui/input.js +1 -6
  92. package/dist/ui/inspector-shell.d.ts +5 -5
  93. package/dist/ui/inspector-shell.js +14 -81
  94. package/dist/ui/intake-form.d.ts +1 -1
  95. package/dist/ui/intake-form.js +21 -97
  96. package/dist/ui/kind-card-grid.js +9 -31
  97. package/dist/ui/library-page-header.js +4 -32
  98. package/dist/ui/list-detail.js +5 -35
  99. package/dist/ui/live-run-banner.d.ts +1 -1
  100. package/dist/ui/live-run-banner.js +5 -15
  101. package/dist/ui/live-status-line.js +6 -24
  102. package/dist/ui/menu.js +7 -24
  103. package/dist/ui/message-bubble.d.ts +3 -3
  104. package/dist/ui/message-bubble.js +5 -44
  105. package/dist/ui/mic-button.d.ts +1 -1
  106. package/dist/ui/mic-button.js +15 -21
  107. package/dist/ui/mic-permission-dialog.js +5 -41
  108. package/dist/ui/notifications-bell.js +9 -43
  109. package/dist/ui/now-cards.d.ts +2 -2
  110. package/dist/ui/now-cards.js +16 -94
  111. package/dist/ui/page-panel.js +11 -11
  112. package/dist/ui/page-shell.js +4 -11
  113. package/dist/ui/parts-renderer.js +51 -149
  114. package/dist/ui/profile-card.js +7 -111
  115. package/dist/ui/progress-checklist.js +11 -49
  116. package/dist/ui/provider-mark.d.ts +2 -2
  117. package/dist/ui/provider-mark.js +9 -16
  118. package/dist/ui/quick-reply-chips.js +6 -14
  119. package/dist/ui/quote-card.js +12 -32
  120. package/dist/ui/reasoning-block.d.ts +1 -1
  121. package/dist/ui/reasoning-block.js +14 -33
  122. package/dist/ui/research-body.js +32 -213
  123. package/dist/ui/rich-empty-state.js +6 -48
  124. package/dist/ui/run-now-button.js +14 -15
  125. package/dist/ui/section.d.ts +1 -1
  126. package/dist/ui/section.js +4 -40
  127. package/dist/ui/select.js +1 -15
  128. package/dist/ui/selection-checkbox.d.ts +1 -1
  129. package/dist/ui/selection-checkbox.js +11 -29
  130. package/dist/ui/settings-panel.js +7 -50
  131. package/dist/ui/shimmer-text.js +3 -6
  132. package/dist/ui/sidebar-item-row.d.ts +1 -1
  133. package/dist/ui/sidebar-item-row.js +9 -39
  134. package/dist/ui/sidebar-panel.js +15 -40
  135. package/dist/ui/sidebar.js +15 -76
  136. package/dist/ui/skeleton.js +3 -7
  137. package/dist/ui/sortable-table.js +29 -72
  138. package/dist/ui/sparkline.js +14 -38
  139. package/dist/ui/stat-grid.js +17 -52
  140. package/dist/ui/status-dot.d.ts +1 -1
  141. package/dist/ui/status-dot.js +8 -20
  142. package/dist/ui/step-list.d.ts +1 -0
  143. package/dist/ui/step-list.js +11 -50
  144. package/dist/ui/switch.js +4 -16
  145. package/dist/ui/table.js +7 -32
  146. package/dist/ui/tabs.js +39 -54
  147. package/dist/ui/textarea.js +10 -19
  148. package/dist/ui/theme-provider.js +54 -78
  149. package/dist/ui/theme-toggle.js +13 -16
  150. package/dist/ui/thinking-indicator.js +3 -15
  151. package/dist/ui/thinking-label.js +16 -35
  152. package/dist/ui/thinking-mark.d.ts +1 -1
  153. package/dist/ui/thinking-mark.js +4 -145
  154. package/dist/ui/time-series-chart.js +43 -174
  155. package/dist/ui/toast.js +12 -20
  156. package/dist/ui/token-mosaic.js +5 -43
  157. package/dist/ui/tool-block.js +18 -70
  158. package/dist/ui/tool-narrative.d.ts +1 -1
  159. package/dist/ui/tool-narrative.js +10 -57
  160. package/dist/ui/tool-picker.js +57 -145
  161. package/dist/ui/tooltip.d.ts +1 -1
  162. package/dist/ui/tooltip.js +4 -33
  163. package/dist/ui/top-bar.js +14 -72
  164. package/dist/ui/trace-waterfall.d.ts +1 -1
  165. package/dist/ui/trace-waterfall.js +21 -93
  166. package/dist/ui/typing-indicator.d.ts +1 -1
  167. package/dist/ui/typing-indicator.js +4 -18
  168. package/dist/ui/view-toggle.js +10 -29
  169. package/dist/ui/voice-waveform.js +3 -11
  170. package/package.json +94 -535
@@ -8,117 +8,13 @@ import { Button } from "./button.js";
8
8
  * Canvas profile card: hero identity, status, action chips, shared
9
9
  * channels, and pinned skills. Deep-links are plain hrefs so the host
10
10
  * router owns navigation.
11
- */ export function ProfileCard({ name, initials, subtitle, statusLabel, statusTone = "neutral", avatarTone = "neutral", tenantMonogram, actions = [], sharedChannels = [], pinnedSkills = [], footer, className }) {
12
- return /*#__PURE__*/ _jsxs("article", {
13
- "data-slot": "profile-card",
14
- className: cn("flex flex-col gap-4 border border-border bg-card p-4", className),
15
- children: [
16
- /*#__PURE__*/ _jsxs("header", {
17
- className: "flex items-start gap-3",
18
- children: [
19
- /*#__PURE__*/ _jsx(Avatar, {
20
- initials: initials,
21
- label: name,
22
- tone: avatarTone,
23
- size: "lg",
24
- ...tenantMonogram === undefined ? {} : {
25
- tenantMonogram
26
- }
27
- }),
28
- /*#__PURE__*/ _jsxs("div", {
29
- className: "min-w-0 flex-1",
30
- children: [
31
- /*#__PURE__*/ _jsxs("div", {
32
- className: "flex flex-wrap items-center gap-2",
33
- children: [
34
- /*#__PURE__*/ _jsx("h2", {
35
- className: "truncate text-base font-semibold",
36
- children: name
37
- }),
38
- statusLabel === undefined ? null : /*#__PURE__*/ _jsx(Badge, {
39
- tone: statusTone,
40
- children: statusLabel
41
- })
42
- ]
43
- }),
44
- subtitle === undefined ? null : /*#__PURE__*/ _jsx("p", {
45
- className: "truncate text-xs text-muted-foreground",
46
- children: subtitle
47
- })
48
- ]
49
- })
50
- ]
51
- }),
52
- actions.length === 0 ? null : /*#__PURE__*/ _jsx("div", {
53
- className: "flex flex-wrap gap-1.5",
54
- children: actions.map((action)=>/*#__PURE__*/ _jsx(Button, {
55
- type: "button",
56
- size: "sm",
57
- variant: action.tone === "primary" ? "primary" : "outline",
58
- onClick: action.onClick,
59
- children: action.label
60
- }, action.id))
61
- }),
62
- sharedChannels.length === 0 ? null : /*#__PURE__*/ _jsxs("section", {
63
- className: "flex flex-col gap-1.5",
64
- children: [
65
- /*#__PURE__*/ _jsx("h3", {
66
- className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground",
67
- children: "Shared channels"
68
- }),
69
- /*#__PURE__*/ _jsx("ul", {
70
- className: "flex flex-col gap-1",
71
- children: sharedChannels.map((channel)=>{
11
+ */
12
+ export function ProfileCard({ name, initials, subtitle, statusLabel, statusTone = "neutral", avatarTone = "neutral", tenantMonogram, actions = [], sharedChannels = [], pinnedSkills = [], footer, className, }) {
13
+ return (_jsxs("article", { "data-slot": "profile-card", className: cn("flex flex-col gap-4 border border-border bg-card p-4", className), children: [_jsxs("header", { className: "flex items-start gap-3", children: [_jsx(Avatar, { initials: initials, label: name, tone: avatarTone, size: "lg", ...(tenantMonogram === undefined ? {} : { tenantMonogram }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("h2", { className: "truncate text-base font-semibold", children: name }), statusLabel === undefined ? null : (_jsx(Badge, { tone: statusTone, children: statusLabel }))] }), subtitle === undefined ? null : (_jsx("p", { className: "truncate text-xs text-muted-foreground", children: subtitle }))] })] }), actions.length === 0 ? null : (_jsx("div", { className: "flex flex-wrap gap-1.5", children: actions.map((action) => (_jsx(Button, { type: "button", size: "sm", variant: action.tone === "primary" ? "primary" : "outline", onClick: action.onClick, children: action.label }, action.id))) })), sharedChannels.length === 0 ? null : (_jsxs("section", { className: "flex flex-col gap-1.5", children: [_jsx("h3", { className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground", children: "Shared channels" }), _jsx("ul", { className: "flex flex-col gap-1", children: sharedChannels.map((channel) => {
72
14
  const href = toSafeHref(channel.href);
73
- return /*#__PURE__*/ _jsx("li", {
74
- children: href === undefined ? /*#__PURE__*/ _jsxs("span", {
75
- className: "text-sm",
76
- children: [
77
- "#",
78
- channel.name
79
- ]
80
- }) : /*#__PURE__*/ _jsxs("a", {
81
- href: href,
82
- className: "text-sm text-foreground hover:underline",
83
- children: [
84
- "#",
85
- channel.name
86
- ]
87
- })
88
- }, channel.id);
89
- })
90
- })
91
- ]
92
- }),
93
- pinnedSkills.length === 0 ? null : /*#__PURE__*/ _jsxs("section", {
94
- className: "flex flex-col gap-1.5",
95
- children: [
96
- /*#__PURE__*/ _jsx("h3", {
97
- className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground",
98
- children: "Pinned skills"
99
- }),
100
- /*#__PURE__*/ _jsx("ul", {
101
- className: "flex flex-wrap gap-1.5",
102
- children: pinnedSkills.map((skill)=>{
15
+ return (_jsx("li", { children: href === undefined ? (_jsxs("span", { className: "text-sm", children: ["#", channel.name] })) : (_jsxs("a", { href: href, className: "text-sm text-foreground hover:underline", children: ["#", channel.name] })) }, channel.id));
16
+ }) })] })), pinnedSkills.length === 0 ? null : (_jsxs("section", { className: "flex flex-col gap-1.5", children: [_jsx("h3", { className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground", children: "Pinned skills" }), _jsx("ul", { className: "flex flex-wrap gap-1.5", children: pinnedSkills.map((skill) => {
103
17
  const href = toSafeHref(skill.href);
104
- return href === undefined ? /*#__PURE__*/ _jsx(Badge, {
105
- tone: "neutral",
106
- children: skill.name
107
- }, skill.id) : /*#__PURE__*/ _jsx("a", {
108
- href: href,
109
- children: /*#__PURE__*/ _jsx(Badge, {
110
- tone: "neutral",
111
- children: skill.name
112
- })
113
- }, skill.id);
114
- })
115
- })
116
- ]
117
- }),
118
- footer === undefined ? null : /*#__PURE__*/ _jsx("footer", {
119
- className: "border-t border-border pt-3",
120
- children: footer
121
- })
122
- ]
123
- });
18
+ return href === undefined ? (_jsx(Badge, { tone: "neutral", children: skill.name }, skill.id)) : (_jsx("a", { href: href, children: _jsx(Badge, { tone: "neutral", children: skill.name }) }, skill.id));
19
+ }) })] })), footer === undefined ? null : (_jsx("footer", { className: "border-t border-border pt-3", children: footer }))] }));
124
20
  }
@@ -6,7 +6,7 @@ const STATUS_LABEL = {
6
6
  pending: "Not started",
7
7
  running: "In progress",
8
8
  done: "Done",
9
- failed: "Failed"
9
+ failed: "Failed",
10
10
  };
11
11
  /**
12
12
  * A list of steps and how far along they are — a long operation reporting
@@ -19,52 +19,14 @@ const STATUS_LABEL = {
19
19
  *
20
20
  * The whole list is `aria-live="polite"`, so steps completing are announced as
21
21
  * they happen without stealing focus from wherever the user actually is.
22
- */ export function ProgressChecklist({ steps, label = "Progress", className }) {
23
- if (steps.length === 0) return null;
24
- return /*#__PURE__*/ _jsx("ol", {
25
- "aria-label": label,
26
- "aria-live": "polite",
27
- className: cn("flex flex-col gap-2.5", className),
28
- children: steps.map((step, index)=>/*#__PURE__*/ _jsxs("li", {
29
- className: "flex items-start gap-3",
30
- children: [
31
- /*#__PURE__*/ _jsx("span", {
32
- "aria-hidden": true,
33
- className: cn("mt-0.5 grid size-5 shrink-0 place-items-center rounded-full border text-[10px] font-semibold", step.status === "done" && "border-transparent bg-success text-success-foreground", step.status === "failed" && "border-transparent bg-destructive text-destructive-foreground", step.status === "running" && "border-primary-emphasis text-primary-emphasis", step.status === "pending" && "border-input text-muted-foreground"),
34
- children: step.status === "done" ? /*#__PURE__*/ _jsx(Check, {
35
- className: "size-3"
36
- }) : step.status === "failed" ? /*#__PURE__*/ _jsx(X, {
37
- className: "size-3"
38
- }) : step.status === "running" ? /*#__PURE__*/ _jsx(StatusDot, {
39
- label: "",
40
- live: true,
41
- tone: "emphasis"
42
- }) : index + 1
43
- }),
44
- /*#__PURE__*/ _jsxs("div", {
45
- className: "flex min-w-0 flex-col gap-0.5",
46
- children: [
47
- /*#__PURE__*/ _jsxs("p", {
48
- className: cn("text-sm leading-snug", step.status === "pending" ? "text-muted-foreground" : "text-foreground"),
49
- children: [
50
- step.label,
51
- " ",
52
- /*#__PURE__*/ _jsxs("span", {
53
- className: "text-xs text-muted-foreground",
54
- children: [
55
- "· ",
56
- STATUS_LABEL[step.status]
57
- ]
58
- })
59
- ]
60
- }),
61
- step.detail === undefined ? null : /*#__PURE__*/ _jsx("p", {
62
- className: "text-xs leading-relaxed text-muted-foreground",
63
- children: step.detail
64
- })
65
- ]
66
- })
67
- ]
68
- }, step.id))
69
- });
22
+ */
23
+ export function ProgressChecklist({ steps, label = "Progress", className, }) {
24
+ if (steps.length === 0)
25
+ return null;
26
+ return (_jsx("ol", { "aria-label": label, "aria-live": "polite", className: cn("flex flex-col gap-2.5", className), children: steps.map((step, index) => (_jsxs("li", { className: "flex items-start gap-3", children: [_jsx("span", { "aria-hidden": true, className: cn("mt-0.5 grid size-5 shrink-0 place-items-center rounded-full border text-[10px] font-semibold", step.status === "done" &&
27
+ "border-transparent bg-success text-success-foreground", step.status === "failed" &&
28
+ "border-transparent bg-destructive text-destructive-foreground", step.status === "running" &&
29
+ "border-primary-emphasis text-primary-emphasis", step.status === "pending" && "border-input text-muted-foreground"), children: step.status === "done" ? (_jsx(Check, { className: "size-3" })) : step.status === "failed" ? (_jsx(X, { className: "size-3" })) : step.status === "running" ? (_jsx(StatusDot, { label: "", live: true, tone: "emphasis" })) : (index + 1) }), _jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [_jsxs("p", { className: cn("text-sm leading-snug", step.status === "pending"
30
+ ? "text-muted-foreground"
31
+ : "text-foreground"), children: [step.label, " ", _jsxs("span", { className: "text-xs text-muted-foreground", children: ["\u00B7 ", STATUS_LABEL[step.status]] })] }), step.detail === undefined ? null : (_jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: step.detail }))] })] }, step.id))) }));
70
32
  }
@@ -14,10 +14,10 @@ export type ProviderMarkProps = {
14
14
  */
15
15
  readonly logo?: ReactNode;
16
16
  readonly size?: "sm" | "md";
17
- readonly className?: string;
17
+ readonly className?: string | undefined;
18
18
  };
19
19
  /** Which service an action goes through. */
20
- export declare function ProviderMark({ provider, logo, size, className }: ProviderMarkProps): import("react").JSX.Element;
20
+ export declare function ProviderMark({ provider, logo, size, className, }: ProviderMarkProps): import("react").JSX.Element;
21
21
  /**
22
22
  * The provider marker for a tool call in a transcript.
23
23
  *
@@ -2,17 +2,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/utils.js";
3
3
  const SIZE_CLASS = {
4
4
  sm: "size-4 text-[8px]",
5
- md: "size-6 text-[10px]"
5
+ md: "size-6 text-[10px]",
6
6
  };
7
- /** Which service an action goes through. */ export function ProviderMark({ provider, logo, size = "sm", className }) {
7
+ /** Which service an action goes through. */
8
+ export function ProviderMark({ provider, logo, size = "sm", className, }) {
8
9
  const label = provider.charAt(0).toUpperCase() + provider.slice(1);
9
- return /*#__PURE__*/ _jsx("span", {
10
- role: "img",
11
- "aria-label": label,
12
- title: label,
13
- className: cn("inline-grid shrink-0 place-items-center overflow-hidden rounded-sm bg-muted font-semibold text-muted-foreground", SIZE_CLASS[size], className),
14
- children: logo ?? provider.slice(0, 2).toUpperCase()
15
- });
10
+ return (_jsx("span", { role: "img", "aria-label": label, title: label, className: cn("inline-grid shrink-0 place-items-center overflow-hidden rounded-sm bg-muted font-semibold text-muted-foreground", SIZE_CLASS[size], className), children: logo ?? provider.slice(0, 2).toUpperCase() }));
16
11
  }
17
12
  /**
18
13
  * The provider marker for a tool call in a transcript.
@@ -20,12 +15,10 @@ const SIZE_CLASS = {
20
15
  * The provider is read off the tool id's `provider__operation` prefix — the
21
16
  * same convention `toolLabel` uses — so a tool with no prefix is local and gets
22
17
  * no marker rather than a guessed one.
23
- */ export function ToolProviderMark({ part, logo, className }) {
18
+ */
19
+ export function ToolProviderMark({ part, logo, className, }) {
24
20
  const [provider, ...rest] = part.toolName.split("__");
25
- if (rest.length === 0 || provider === undefined || provider === "") return null;
26
- return /*#__PURE__*/ _jsx(ProviderMark, {
27
- provider: provider,
28
- logo: logo,
29
- className: className
30
- });
21
+ if (rest.length === 0 || provider === undefined || provider === "")
22
+ return null;
23
+ return _jsx(ProviderMark, { provider: provider, logo: logo, className: className });
31
24
  }
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx as _jsx } from "react/jsx-runtime";
2
3
  import { cn } from "../lib/utils.js";
3
4
  /**
@@ -7,18 +8,9 @@ import { cn } from "../lib/utils.js";
7
8
  *
8
9
  * Sending is the host's job: this reports which chip was chosen and lets the
9
10
  * host decide whether that fills the composer or sends immediately.
10
- */ export function QuickReplyChips({ replies, onSelect, className }) {
11
- if (replies.length === 0) return null;
12
- return /*#__PURE__*/ _jsx("ul", {
13
- "aria-label": "Suggested replies",
14
- className: cn("flex flex-wrap gap-2", className),
15
- children: replies.map((reply)=>/*#__PURE__*/ _jsx("li", {
16
- children: /*#__PURE__*/ _jsx("button", {
17
- type: "button",
18
- onClick: ()=>onSelect(reply),
19
- className: "rounded-full border border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-background hover:text-foreground",
20
- children: reply.label
21
- })
22
- }, reply.id))
23
- });
11
+ */
12
+ export function QuickReplyChips({ replies, onSelect, className, }) {
13
+ if (replies.length === 0)
14
+ return null;
15
+ return (_jsx("ul", { "aria-label": "Suggested replies", className: cn("flex flex-wrap gap-2", className), children: replies.map((reply) => (_jsx("li", { children: _jsx("button", { type: "button", onClick: () => onSelect(reply), className: "rounded-full border border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-background hover:text-foreground", children: reply.label }) }, reply.id))) }));
24
16
  }
@@ -1,4 +1,5 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ "use client";
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
3
  import { useState } from "react";
3
4
  import { cn } from "../lib/utils.js";
4
5
  /**
@@ -21,9 +22,11 @@ import { cn } from "../lib/utils.js";
21
22
  * `<blockquote>` and `<cite>`, because that is what this is. The quotation and
22
23
  * its attribution are related in the markup rather than being two adjacent
23
24
  * strings that happen to sit near each other.
24
- */ export function QuoteCard({ quotes, storageKey, className }) {
25
- const [index] = useState(()=>{
26
- if (storageKey === undefined || quotes.length === 0) return 0;
25
+ */
26
+ export function QuoteCard({ quotes, storageKey, className }) {
27
+ const [index] = useState(() => {
28
+ if (storageKey === undefined || quotes.length === 0)
29
+ return 0;
27
30
  try {
28
31
  const raw = window.localStorage.getItem(storageKey);
29
32
  const parsed = raw === null ? -1 : Number.parseInt(raw, 10);
@@ -31,36 +34,13 @@ import { cn } from "../lib/utils.js";
31
34
  const next = (last + 1) % quotes.length;
32
35
  window.localStorage.setItem(storageKey, String(next));
33
36
  return next;
34
- } catch {
37
+ }
38
+ catch {
35
39
  return 0;
36
40
  }
37
41
  });
38
42
  const quote = quotes[index % Math.max(quotes.length, 1)];
39
- if (quote === undefined) return null;
40
- return /*#__PURE__*/ _jsxs("figure", {
41
- className: cn("w-full max-w-xs rounded-xl border border-border bg-card/90 p-6 backdrop-blur-sm", className),
42
- children: [
43
- /*#__PURE__*/ _jsxs("blockquote", {
44
- className: "text-base leading-relaxed whitespace-pre-line text-card-foreground",
45
- children: [
46
- "“",
47
- quote.text,
48
- "”"
49
- ]
50
- }),
51
- quote.author === undefined ? null : /*#__PURE__*/ _jsxs("figcaption", {
52
- className: "mt-4 flex items-center gap-3",
53
- children: [
54
- /*#__PURE__*/ _jsx("span", {
55
- "aria-hidden": true,
56
- className: "h-px flex-1 bg-border"
57
- }),
58
- /*#__PURE__*/ _jsx("cite", {
59
- className: "text-xs text-muted-foreground not-italic",
60
- children: quote.author
61
- })
62
- ]
63
- })
64
- ]
65
- });
43
+ if (quote === undefined)
44
+ return null;
45
+ return (_jsxs("figure", { className: cn("w-full max-w-xs rounded-xl border border-border bg-card/90 p-6 backdrop-blur-sm", className), children: [_jsxs("blockquote", { className: "text-base leading-relaxed whitespace-pre-line text-card-foreground", children: ["\u201C", quote.text, "\u201D"] }), quote.author === undefined ? null : (_jsxs("figcaption", { className: "mt-4 flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "h-px flex-1 bg-border" }), _jsx("cite", { className: "text-xs text-muted-foreground not-italic", children: quote.author })] }))] }));
66
46
  }
@@ -8,7 +8,7 @@ export type ReasoningBlockProps = {
8
8
  /** Summary once idle when no `durationLabel` is supplied. Defaults to "Thinking". */
9
9
  readonly idleLabel?: string;
10
10
  /** e.g. "Thought for 4s". Becomes the summary once reasoning has stopped streaming. */
11
- readonly durationLabel?: string;
11
+ readonly durationLabel?: string | undefined;
12
12
  readonly defaultOpen?: boolean;
13
13
  /**
14
14
  * Controlled open state. Pair with `onOpenChange` to lift it to a parent —
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { ChevronRight } from "lucide-react";
3
4
  import { useControllableState } from "../hooks/use-controllable-state.js";
@@ -12,49 +13,29 @@ import { cn } from "../lib/utils.js";
12
13
  * A native `<details>`, not a div with state: it gets the disclosure
13
14
  * semantics, keyboard behaviour and find-in-page expansion from the browser,
14
15
  * and those are three things a hand-rolled version gets wrong.
15
- */ export function ReasoningBlock({ text, streaming = false, streamingLabel = "Thinking…", idleLabel = "Thinking", durationLabel, defaultOpen = false, open: openProp, onOpenChange, className }) {
16
+ */
17
+ export function ReasoningBlock({ text, streaming = false, streamingLabel = "Thinking…", idleLabel = "Thinking", durationLabel, defaultOpen = false, open: openProp, onOpenChange, className, }) {
16
18
  const [open, setOpen] = useControllableState({
17
19
  value: openProp,
18
20
  defaultValue: defaultOpen,
19
21
  onChange: onOpenChange,
20
- name: "ReasoningBlock"
22
+ name: "ReasoningBlock",
21
23
  });
22
- if (text.trim().length === 0) return null;
23
- const summary = streaming ? streamingLabel : durationLabel ?? idleLabel;
24
- return /*#__PURE__*/ _jsxs("details", {
25
- "data-slot": "reasoning-block",
26
- open: open,
24
+ if (text.trim().length === 0)
25
+ return null;
26
+ const summary = streaming ? streamingLabel : (durationLabel ?? idleLabel);
27
+ return (_jsxs("details", { "data-slot": "reasoning-block", open: open,
27
28
  // The browser fires `toggle` for any `open` attribute change — prop-driven
28
29
  // ones included — so a bare setOpen would echo the parent's own commands
29
30
  // back through onOpenChange. Reporting only divergence means exactly one
30
31
  // callback per user activation, and none when a parent drives `open`.
31
- onToggle: (event)=>{
32
+ onToggle: (event) => {
32
33
  const domOpen = event.currentTarget.open;
33
- if (domOpen !== open) setOpen(domOpen);
34
- },
35
- className: cn("text-xs", className),
36
- children: [
37
- /*#__PURE__*/ _jsxs("summary", {
38
- className: cn(// `relative` plus the `::after` pseudo-element extends the
34
+ if (domOpen !== open)
35
+ setOpen(domOpen);
36
+ }, className: cn("text-xs", className), children: [_jsxs("summary", { className: cn(
37
+ // `relative` plus the `::after` pseudo-element extends the
39
38
  // effective hit area to 40px tall without changing the row's own
40
39
  // padding/density — see design-engineering.md's hit-area pattern.
41
- "relative flex cursor-pointer list-none items-center gap-1.5 rounded-md px-2 py-1.5 text-muted-foreground transition-colors after:absolute after:inset-x-0 after:top-1/2 after:h-10 after:-translate-y-1/2 hover:bg-muted hover:text-foreground", "[&::-webkit-details-marker]:hidden"),
42
- children: [
43
- /*#__PURE__*/ _jsx(ChevronRight, {
44
- className: cn("size-3.5 shrink-0 transition-transform duration-200 ease-out", open && "rotate-90"),
45
- "aria-hidden": true
46
- }),
47
- /*#__PURE__*/ _jsx("span", {
48
- "aria-live": "polite",
49
- children: summary
50
- })
51
- ]
52
- }),
53
- /*#__PURE__*/ _jsx("p", {
54
- "aria-busy": streaming,
55
- className: "mt-1 ml-4 border-l border-border pl-3 leading-relaxed whitespace-pre-wrap text-muted-foreground [animation:corbits-rail-block-in_200ms_var(--ease-out)_both]",
56
- children: text
57
- }, open ? "open" : "closed")
58
- ]
59
- });
40
+ "relative flex cursor-pointer list-none items-center gap-1.5 rounded-md px-2 py-1.5 text-muted-foreground transition-colors after:absolute after:inset-x-0 after:top-1/2 after:h-10 after:-translate-y-1/2 hover:bg-muted hover:text-foreground", "[&::-webkit-details-marker]:hidden"), children: [_jsx(ChevronRight, { className: cn("size-3.5 shrink-0 transition-transform duration-200 ease-out", open && "rotate-90"), "aria-hidden": true }), _jsx("span", { "aria-live": "polite", children: summary })] }), _jsx("p", { "aria-busy": streaming, className: "mt-1 ml-4 border-l border-border pl-3 leading-relaxed whitespace-pre-wrap text-muted-foreground [animation:corbits-rail-block-in_200ms_var(--ease-out)_both]", children: text }, open ? "open" : "closed")] }));
60
41
  }