refactor(chat): share composer, scroll follow and jump control across both chat surfaces

The rectification session rendered its own textarea (no length ceiling,
no count), its own rAF scroll follow with a sticky-scroll helper, and its
own jump chip styled differently from the main chat's inline Tailwind
button, while the main chat re-ran scrollTo on every streamed token and
added a smooth scroll on settle. ChatComposer now accepts a controlled
value so the rectification surface reuses it without touching the main
draft store; useConversationScrollAnchor owns the follow through a
ResizeObserver, one frame per content change, for both surfaces; a
single JumpToLatestButton replaces both chips; the 720px transcript
override is gone. DESIGN.md records the shared composer, the jump
control, the reading width and the two shadow tokens.

BUG-477 BUG-478

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
This commit is contained in:
Jesse_Chen
2026-09-01 23:26:23 +00:00
parent eeb82dfdc4
commit f542c02490
17 changed files with 329 additions and 264 deletions
+32
View File
@@ -7330,3 +7330,35 @@
- 相关记录:BUG-474、BUG-475
- 复发自:无
- 修复版本:待发布
## BUG-477 | 生时校正会话的输入框没有字数上限,也没有接近上限的计数
- 状态:resolved
- 首次发现:2026-09-01
- 最近更新:2026-09-02
- 影响面:`rectification-agentic-chat.tsx``chat-composer.tsx`
- 用户现象:校正会话里可以无限输入;主对话在剩余 50 字时会出现计数并在到顶时变红(BUG-447),校正会话什么都没有。停止按钮、发送按钮、textarea 也是另一份手写的。
- 触发条件:任何一次校正会话输入。
- 根因:校正面用裸 `<Textarea>` + 两个 `<Button>` 自己拼输入框,没有 `maxLength`,也没有接 `CharacterRemaining``ChatComposer` 只会读主会话的 `composer-draft` 外部 store,校正面有自己的 `draft` state,所以一直没复用。
- 修复:`ChatComposer` 新增可选受控 `value``remainingId`:有 `value` 时以其为准(store 订阅仍在组件内,不改主会话行为),校正面传 `value={draft}`,不写主会话 store。校正面渲染 `ChatComposer``maxLength=500`,与主对话同上限)并在 `composer-footer``CharacterRemaining`;三段 placeholder、Enter/Shift+Enter/`isComposing` 处理、停止按钮文案原样保留。
- 验证:`composer-isolation-contract`(校正传 `value`、不 import `composer-draft`)、`character-remaining-contract``composer-ime-contract``rectification-agentic-entry`
- 防复发:不得再手写第二个聊天输入框;新增会话面一律渲染 `ChatComposer`,自有草稿走 `value`
- 相关记录:BUG-447、BUG-478
- 复发自:无
- 修复版本:待发布
## BUG-478 | 滚动跟随与「跳到最新」在两个会话面各写一份,主会话每个 token 都触发一次 scrollTo
- 状态:resolved
- 首次发现:2026-09-01
- 最近更新:2026-09-02
- 影响面:`use-conversation-scroll-anchor.ts``page.tsx``rectification-agentic-chat.tsx``rectification-sticky-scroll.ts`(删除)、`globals.css`
- 用户现象:主会话流式期间每个 token 触发一次 `scrollTo`,回答结束瞬间再补一次 smooth 滚动,看起来"先跳到底再滑一下";校正面是另一套 rAF 跟随;「跳到最新」按钮两份不同样式(主会话内联 Tailwind `shadow-md`、校正面 `--shadow-soft`,文案一个「跳到最新」一个「回到最新」)。
- 触发条件:任意流式回答;向上翻阅历史。
- 根因:`page.tsx` 的滚动 effect 以 `activeStreamingText` 为依赖;校正面自带 `followTailRef` / `followLatestContent` / `rectification-sticky-scroll.ts`;按钮各写各的。
- 修复:跟随并入 `useConversationScrollAnchor``ResizeObserver` 观察滚动容器的子元素、`MutationObserver` 跟踪子元素增删,anchored 时下一帧 `scrollTop = scrollHeight``resetKey` 变化立即落底;不再在结算时补 smooth 滚动。`page.tsx` 的滚动 effect 删除;校正面接入同一 hook(`resetKey = caseId`),删除 `rectification-sticky-scroll.ts` 及其全部胶水。新增 `JumpToLatestButton``.jump-to-latest``--shadow-elevated`、44px、focus ring),两面共用,文案统一「跳到最新」带箭头;`page.tsx` 内联 Tailwind 版与 `.rectification-jump-latest` 删除。校正 `.message-list` 720px 覆写删除,与主会话同 900px。
- 验证:`chat-notice-and-scroll-contract`follow 在 hook 内、anchored 守卫在赋值前、`page.tsx``scrollTo`)、`chat-navigation-a11y-contract``chat-stream-layout``rectification-agentic-entry``rectification-answer-choice`
- 防复发:任何会话面不得自行监听 scroll 或按内容变化调 `scrollTo`;跟随只经 `useConversationScrollAnchor`,跳到最新只经 `JumpToLatestButton`
- 相关记录:BUG-477
- 复发自:无
- 修复版本:待发布