Repository navigation
Commit 38bab22
fix(app-shell): a chat pane too narrow for the preview split previews the way a phone does (#27467)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8NKwKGQBkpf1QUFK6NsWFT5)_
Fixes #27420
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:助手聊天面板放不下「聊天 + 预览」并排(两者最小宽度合计
780px)时,改走手机端已有的预览方式:聊天占满宽度,输入框上方给「预览应用」按钮,预览以整块浮层打开,关闭回到聊天。780px
及以上保持原来的并排分栏和拖拽分隔条。
- 为什么改:1024px 窗口下应用内助手的草稿预览被挤出面板,380px 的 iframe 只露出 136px,客户看不到改动。
- 风险与回滚:只改 `AiChatPage.tsx` 的分栏判定(新增 `isTooNarrowForSplit` 与
`tooNarrow`,原 `isMobile` 的五处开关改读 `phonePreview`);宽度足够时行为不变。回滚 = revert 本
PR。
- 先看:`AiChatPage.tsx` 的 `useResizableChatPane` 新增的 `tooNarrow` 测量与
`phonePreview`;再看新测试 `AiChatPage.narrowSplit-27420.test.tsx`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/console/ai/__tests__/AiChatPage.narrowSplit-27420.test.tsx`,预期
6 passed。
- 需要你做的:无,席位落地。
## What changes
`ui/packages/app-shell/src/console/ai/AiChatPage.tsx` only, as the seat
ruled on the card (reuse the phone path):
- **`isTooNarrowForSplit(containerWidth)`**, pure and exported beside
`clampChatPaneWidth`: true below `CHAT_PANE_MIN_WIDTH +
CHAT_PREVIEW_MIN_WIDTH` (780 px); an unmeasured container (0) is not
narrow, the same convention `clampChatPaneWidth` uses.
- **`useResizableChatPane` returns `tooNarrow`.** It is read from the
pane's own root (the existing `containerRef`, present in both
presentations), in a layout effect with its own `ResizeObserver` that
runs whether or not the split is open, so a narrow pane never paints the
split first. The existing re-clamp observer is unchanged and still runs
only while the split is open.
- **`phonePreview = isMobile || split.tooNarrow`** replaces `isMobile`
at the five switch points: the beside-chat split (`desktopSplit`), the
pill row (`mobilePreviewAvailable`), the two Preview-tap auto-opens, and
the full-surface overlay (`ai-chat-mobile-canvas`). No new widget, no
change to the dock's width or the app page beside it.
`ui/packages/app-shell/src/console/ai/__tests__/clampChatPaneWidth.test.ts`
gains the threshold cases; `AiChatPage.narrowSplit-27420.test.tsx` is
new. One patch changeset (`@object-ui/app-shell`, `@object-ui/console`).
## Why
#27420: in the console dock at a 1024 px window the dock is maximized to
504 px while a preview is open, the chat column keeps its 360 px floor
and is `shrink-0`, and the Live Canvas is laid out past the dock's edge.
## Acceptance notes
- **Measured in real Chromium** (`/opt/pw-browsers/chromium`, 768 px
tall), on the real `ChatDockPanel` with the real `useChatDockState` (so
the canvas auto-maximize is real), the real `ChatDockConversation`,
`ChatPane`, `ChatbotEnhanced` and `LiveCanvas`, served by the console's
own Vite config with its Tailwind sheet. Fixtures: the app page beside
the rail is a `min-w-0 flex-1` box; the chat hooks are inert and a
hidden handle calls `onPreviewDraftApp` as a draft card's Preview does
(the stand-ins of `AiChatPage.previewPillInFlow-13068.test.tsx`); the
agent catalog, metadata, adapter and auth hooks are stubbed. The harness
was scratch and is not committed. "Before" is this branch with the
switch ablated back to `isMobile` alone.
| Window | Dock | Before: presentation · preview iframe x-range ·
visible | After: presentation · preview iframe x-range · visible |
|---|---|---|---|
| 1024 | 504 | split · 888–1221 · **136 px** | overlay · 522–1024 · 502
px (whole) |
| 1280 | 760 | split · 888–1280 · 392 px (preview below its 420 px
minimum) | overlay · 522–1280 · 758 px (whole) |
| 1440 | 920 | split · 888–1440 · 552 px | split · 888–1440 · 552 px
(unchanged) |
The 1024 reading reproduces the card's figures (iframe from x 888, 136
px visible). `document.scrollWidth` equals the window width in every
row.
- **The dock keeps the split only from a 1300 px window.** The maximized
dock is the window minus the 520 px the page beside it keeps
(`maximizedDockWidth`), so the 780 px threshold is a 1300 px window. At
1280 px the dock now takes the phone path where it used to show a
squeezed (not clipped) split. That follows the ruled threshold; recorded
here so the seat sees it.
- **Other hosts of the same pane follow the same rule.** The full-page
`/ai` chat keeps its split whenever its pane is at least 780 px (pinned
at 780 px in the new test); the Studio copilot's narrow slot, which also
mounts `ChatPane`, now previews through the overlay instead of
overflowing.
- **No flip-flop.** The width is read from the pane root, whose width
the presentation does not change (the overlay is `absolute inset-0`
inside it, the split's children are inside it too). The new test replays
resizes across the threshold and repeats each width (779, 780) to show a
held width never switches back.
- An auto-drafted preview (an artifact landing, not a Preview tap) in a
narrow pane offers the pill without covering the chat, as on a phone.
## Verification
Head `605e6e5c` (branch merged with `origin/main` `bbb49c9f`); every
reading below is from that tree.
- New pins: `AiChatPage.narrowSplit-27420.test.tsx` 6/6 and
`clampChatPaneWidth.test.ts` 8/8 passed.
- Ablation (`scripts/ablation-replace.mjs`, anchor `const phonePreview =
isMobile || split.tooNarrow;` replaced by `const phonePreview =
isMobile;`, landed 1 to 0): the new suite went red, 3 failed (both 760
px cases and the resize case), 3 passed (the 780 px and unmeasured
cases, which do not depend on it). Restored: blob equals `HEAD` and `git
diff HEAD` is empty.
- `pnpm --dir ui exec vitest run packages/app-shell/src/console/ai/
packages/app-shell/src/layout/`: 165 files, 1024 tests passed.
- `pnpm --filter @object-ui/app-shell run type-check`: exit 0. `pnpm
--dir ui run check:new-line-citations`: 0 new. `pnpm
check:changeset-fixed`: exit 0.
<details><summary>Derived gates: 35 of 35 run, all exit 0</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 35 commands; each was run and its
exit recorded before any pipe; `--ran` reconciles 35 derived, 35 run, 0
not measured. Among them `pnpm --dir ui exec vitest run scripts/`: 169
files passed, 2 skipped. Tier: `dispatch-gates --tier` reports no
path-derived mandate. Changed lines 378 against the 3000 threshold.
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(not touched)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (left to CI)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: not touched.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxbXTbdoAxiCMJjYAtze)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent fbaacfe commit 38bab22
4 files changed
Lines changed: 367 additions & 11 deletions
File tree
- .changeset
- ui/packages/app-shell/src/console/ai
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
578 | 578 | | |
579 | 579 | | |
580 | 580 | | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
581 | 592 | | |
582 | 593 | | |
583 | 594 | | |
| |||
591 | 602 | | |
592 | 603 | | |
593 | 604 | | |
| 605 | + | |
| 606 | + | |
594 | 607 | | |
595 | 608 | | |
596 | 609 | | |
| |||
641 | 654 | | |
642 | 655 | | |
643 | 656 | | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
644 | 674 | | |
645 | 675 | | |
646 | 676 | | |
| |||
682 | 712 | | |
683 | 713 | | |
684 | 714 | | |
685 | | - | |
| 715 | + | |
686 | 716 | | |
687 | 717 | | |
688 | 718 | | |
| |||
1771 | 1801 | | |
1772 | 1802 | | |
1773 | 1803 | | |
| 1804 | + | |
| 1805 | + | |
| 1806 | + | |
| 1807 | + | |
1774 | 1808 | | |
1775 | 1809 | | |
1776 | 1810 | | |
| |||
2461 | 2495 | | |
2462 | 2496 | | |
2463 | 2497 | | |
2464 | | - | |
2465 | | - | |
2466 | | - | |
| 2498 | + | |
| 2499 | + | |
| 2500 | + | |
| 2501 | + | |
2467 | 2502 | | |
2468 | 2503 | | |
2469 | 2504 | | |
| |||
2487 | 2522 | | |
2488 | 2523 | | |
2489 | 2524 | | |
2490 | | - | |
| 2525 | + | |
2491 | 2526 | | |
2492 | 2527 | | |
2493 | 2528 | | |
| |||
2851 | 2886 | | |
2852 | 2887 | | |
2853 | 2888 | | |
2854 | | - | |
| 2889 | + | |
2855 | 2890 | | |
2856 | 2891 | | |
2857 | 2892 | | |
| |||
2865 | 2900 | | |
2866 | 2901 | | |
2867 | 2902 | | |
2868 | | - | |
| 2903 | + | |
2869 | 2904 | | |
2870 | 2905 | | |
2871 | 2906 | | |
| |||
2922 | 2957 | | |
2923 | 2958 | | |
2924 | 2959 | | |
2925 | | - | |
| 2960 | + | |
2926 | 2961 | | |
2927 | 2962 | | |
2928 | 2963 | | |
2929 | 2964 | | |
2930 | | - | |
| 2965 | + | |
2931 | 2966 | | |
2932 | 2967 | | |
2933 | 2968 | | |
| |||
0 commit comments