Skip to content

Commit 044d2ea

Browse files
committed
feat(chat)!: remove the old chat components
There is now one way to build chat UI: the Conversation family. Remove ChatThread, ChatComposer, ChatInput, ChatPanel, MessageBubble, ApprovalCard, ToolBlock, ToolNarrative, ReasoningBlock and the modules built only on them, with their stories, tests and browser specs. The part types move into the conversation module unchanged, so their names stay stable. ToolProviderMark takes a tool name instead of a part. README gains "Upgrading from 0.3", which maps every removed export to what replaced it.
1 parent 22da640 commit 044d2ea

46 files changed

Lines changed: 277 additions & 2843 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ jobs:
2929
mkdir -p "$RUNNER_TEMP/c" && cd "$RUNNER_TEMP/c"
3030
npm init -y >/dev/null && npm pkg set type=module >/dev/null
3131
npm install "$TARBALL"
32-
node -e 'import("@corbits/react-ui").then((m) => { for (const n of ["Button", "ChatThread", "Badge"]) if (typeof m[n] !== "function") throw new Error("missing export: " + n); })'
32+
node -e 'import("@corbits/react-ui").then((m) => { for (const n of ["Button", "Conversation", "Badge"]) if (typeof m[n] !== "function") throw new Error("missing export: " + n); })'

‎README.md‎

Lines changed: 160 additions & 46 deletions
Large diffs are not rendered by default.

‎e2e/approval-card.spec.ts‎

Lines changed: 0 additions & 21 deletions
This file was deleted.

‎e2e/chat-thread.spec.ts‎

Lines changed: 0 additions & 23 deletions
This file was deleted.

‎e2e/fixtures.tsx‎

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ import { useEffect, useLayoutEffect, useRef, useState, Profiler } from "react";
22
import type { ReactNode } from "react";
33

44
import {
5-
ApprovalCard,
65
AuthLayout,
76
Button,
8-
ChatThread,
97
Conversation,
108
ConversationContent,
119
ConversationItem,
@@ -17,8 +15,6 @@ import {
1715
ThemeProvider,
1816
ThemeToggle,
1917
ThinkingMark,
20-
type ApprovalRequest,
21-
type ChatMessage,
2218
type ConversationScrollPolicy,
2319
useConversation,
2420
PromptInput,
@@ -88,13 +84,6 @@ import {
8884
type CommandPaletteGroup,
8985
} from "@corbits/react-ui/ui/command-palette";
9086

91-
const REQUEST: ApprovalRequest = {
92-
id: "req-1",
93-
headline: "Post to #sales (Slack)",
94-
requestedBy: "Scout",
95-
details: [{ label: "Message", value: "Q3 numbers are in." }],
96-
};
97-
9887
const GROUPS: CommandPaletteGroup[] = [
9988
{
10089
id: "pages",
@@ -116,21 +105,6 @@ function useEventLog() {
116105
};
117106
}
118107

119-
function Approval({ state }: { state: "idle" | "approving" }) {
120-
const { log, record } = useEventLog();
121-
return (
122-
<>
123-
<ApprovalCard
124-
request={REQUEST}
125-
state={state}
126-
onApprove={() => record("approve")}
127-
onReject={() => record("reject")}
128-
/>
129-
{log}
130-
</>
131-
);
132-
}
133-
134108
function Palette() {
135109
const [open, setOpen] = useState(false);
136110
const [query, setQuery] = useState("");
@@ -154,32 +128,6 @@ function Palette() {
154128
);
155129
}
156130

157-
const CHAT: ChatMessage[] = [
158-
{
159-
id: "m1",
160-
role: "user",
161-
createdAt: "2026-01-01T09:00:00Z",
162-
parts: [{ type: "text", text: "What changed today?" }],
163-
},
164-
{
165-
id: "m2",
166-
role: "agent",
167-
createdAt: "2026-01-01T09:00:04Z",
168-
parts: [
169-
{ type: "reasoning", text: "Check the commit log first." },
170-
{
171-
type: "tool",
172-
toolCallId: "t1",
173-
toolName: "git__log",
174-
label: "Read today's commits",
175-
state: "done",
176-
output: "3 commits",
177-
},
178-
{ type: "text", text: "Three commits landed today." },
179-
],
180-
},
181-
];
182-
183131
function SelectField() {
184132
const [value, setValue] = useState("a");
185133
const { log, record } = useEventLog();
@@ -1433,14 +1381,7 @@ function ConversationThreadScenario() {
14331381

14341382
export const scenarios: Record<string, () => ReactNode> = {
14351383
smoke: () => <Button>Ready</Button>,
1436-
"approval-card": () => <Approval state="idle" />,
1437-
"approval-card-busy": () => <Approval state="approving" />,
14381384
"command-palette": () => <Palette />,
1439-
"chat-thread": () => (
1440-
<div style={{ display: "flex", flexDirection: "column", height: 480 }}>
1441-
<ChatThread messages={CHAT} identity={{ name: "Scout" }} />
1442-
</div>
1443-
),
14441385
select: () => <SelectField />,
14451386
"filter-chip": () => <Chip />,
14461387
"dictation-denied": () => <DictationStatusLine state="denied" />,

‎e2e/stories-a11y.known.json‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
"chat-prompt-input--suggestions-open (light): color-contrast-unmeasured",
1313
"chat-prompt-input--with-tokens (dark): color-contrast-unmeasured",
1414
"chat-prompt-input--with-tokens (light): color-contrast-unmeasured",
15-
"chat-tool-block--long-output-scrolls-in-place (dark): scrollable-region-focusable",
16-
"chat-tool-block--long-output-scrolls-in-place (light): scrollable-region-focusable",
1715
"primitives-avatar--orbit (dark): color-contrast-unmeasured",
1816
"primitives-avatar--orbit (light): color-contrast-unmeasured",
1917
"primitives-avatar--stack-with-status (dark): color-contrast-unmeasured",

‎src/hooks/use-attachments.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
22
import { Activity, StrictMode, act, createElement, useState } from "react";
33
import { createRoot } from "react-dom/client";
44

5-
import type { PartFile } from "../lib/chat-parts.js";
5+
import type { PartFile } from "../lib/conversation.js";
66
import type { AttachmentData } from "../ui/attachments.js";
77
import {
88
useAttachments,

‎src/hooks/use-controllable-state.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@ const isProduction =
1818
/**
1919
* The controlled-or-uncontrolled resolution every prop pair shaped like
2020
* `open`/`onOpenChange` needs: track state internally, but defer to `value`
21-
* whenever the caller supplies one. `useDismissablePopover`, `ToolBlock` and
22-
* `ToolNarrative` each want exactly this and previously each wrote their own
23-
* ternary for it; this is the one place it lives now.
21+
* whenever the caller supplies one. Every such pair resolves through here
22+
* rather than writing its own ternary.
2423
*
2524
* The returned setter accepts a value or a React-style updater
2625
* (`setOpen((prev) => !prev)`), same as `useState`.

‎src/hooks/use-delayed-autofocus.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import { useEffect, type RefObject } from "react";
22

3-
import { CHAT_DOCK_AUTOFOCUS_DELAY_MS } from "../ui/chat-dock-timing.js";
3+
/**
4+
* Roughly a typical panel entrance (a few hundred milliseconds), so focus
5+
* never lands on an element that is still moving.
6+
*/
7+
const DEFAULT_DELAY_MS = 280;
48

59
/**
6-
* Focuses the given element shortly after `active` turns true — the composer
7-
* wants to autofocus once the dock has finished popping open, not while it is
8-
* still mid-animation, so the delay is deliberate rather than a magic number.
9-
* `delayMs` defaults to `CHAT_DOCK_AUTOFOCUS_DELAY_MS`, which is pinned `>=`
10-
* the dock's own entrance duration so focus never lands mid-animation.
10+
* Focuses the given element shortly after `active` turns true: an element
11+
* that animates in takes focus once it has settled, not while it is still
12+
* mid-animation. Pass a `delayMs` at least as long as the entrance it waits
13+
* for.
1114
*/
1215
export function useDelayedAutofocus<T extends HTMLElement>(
1316
ref: RefObject<T | null>,
1417
active: boolean,
15-
delayMs = CHAT_DOCK_AUTOFOCUS_DELAY_MS,
18+
delayMs = DEFAULT_DELAY_MS,
1619
): void {
1720
useEffect(() => {
1821
if (!active) return;

‎src/index.ts‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ export * from "./hooks/use-file-drop.js";
3131
export * from "./hooks/use-media-viewer.js";
3232
export * from "./lib/artifact.js";
3333
export * from "./lib/chart-palette.js";
34-
export * from "./lib/chat-message.js";
35-
export * from "./lib/chat-parts.js";
3634
export * from "./lib/metrics.js";
3735
export * from "./lib/now-item.js";
3836
export * from "./lib/relative-time.js";
@@ -46,9 +44,7 @@ export * from "./lib/conversation-activity.js";
4644
export * from "./lib/media-kind.js";
4745
export * from "./lib/attachment-limits.js";
4846
export * from "./lib/prompt-tokens.js";
49-
export * from "./ui/agent-turn.js";
5047
export * from "./ui/animated-number.js";
51-
export * from "./ui/approval-card.js";
5248
export * from "./ui/artifact-body.js";
5349
export * from "./ui/artifact-notice.js";
5450
export * from "./ui/avatar.js";
@@ -61,10 +57,6 @@ export * from "./ui/button.js";
6157
export * from "./ui/card.js";
6258
export * from "./ui/category-bars.js";
6359
export * from "./ui/chart-frame.js";
64-
export * from "./ui/chat-composer.js";
65-
export * from "./ui/chat-input.js";
66-
export * from "./ui/chat-panel.js";
67-
export * from "./ui/chat-thread.js";
6860
export * from "./ui/checkbox.js";
6961
export * from "./ui/compare-body.js";
7062
export * from "./ui/confirm-button.js";
@@ -87,19 +79,15 @@ export * from "./ui/library-page-header.js";
8779
export * from "./ui/list-detail.js";
8880
export * from "./ui/live-run-banner.js";
8981
export * from "./ui/live-status-line.js";
90-
export * from "./ui/message-bubble.js";
9182
export * from "./ui/mic-button.js";
9283
export * from "./ui/notifications-bell.js";
9384
export * from "./ui/now-cards.js";
9485
export * from "./ui/page-panel.js";
9586
export * from "./ui/page-shell.js";
96-
export * from "./ui/parts-renderer.js";
9787
export * from "./ui/profile-card.js";
9888
export * from "./ui/progress-checklist.js";
9989
export * from "./ui/provider-mark.js";
100-
export * from "./ui/quick-reply-chips.js";
10190
export * from "./ui/quote-card.js";
102-
export * from "./ui/reasoning-block.js";
10391
export * from "./ui/research-body.js";
10492
export * from "./ui/rich-empty-state.js";
10593
export * from "./ui/run-now-button.js";
@@ -128,8 +116,6 @@ export * from "./ui/thinking-label.js";
128116
export * from "./ui/thinking-mark.js";
129117
export * from "./ui/time-series-chart.js";
130118
export * from "./ui/token-mosaic.js";
131-
export * from "./ui/tool-block.js";
132-
export * from "./ui/tool-narrative.js";
133119
export * from "./ui/tool-picker.js";
134120
export * from "./ui/top-bar.js";
135121
export * from "./ui/trace-waterfall.js";

0 commit comments

Comments
 (0)