FN-7204: make narrow chat messages full width

Narrow chat surfaces now let messages span their constrained container width.

- Add a ChatView container query that makes all message variants full-width in narrow hosts such as Quick Chat popups and the right dock.
- Update the mobile bubble cap to full width while preserving tablet assistant widening and desktop caps.
- Cover the responsive CSS contracts in dashboard tests and document the behavior with a patch changeset.

Files changed:
 .changeset/fn-7204-full-width-chat-messages.md       |  7 +++++++
 docs/dashboard-guide.md                              |  6 +++---
 packages/dashboard/app/components/ChatView.css       | 12 +++++++++++-
 .../__tests__/ChatView.core-contracts.test.tsx       | 20 +++++++++++++++++---
 .../components/__tests__/ChatView.mobile.test.tsx    |  4 ++--
 5 files changed, 40 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7204
Fusion-Task-Lineage: 19da0d46-f0bf-46e7-9f87-900c5184f378
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-06-28 14:56:52 -07:00
parent b2e1c3efc2
commit befb49b1e6
5 changed files with 40 additions and 9 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Chat messages now use the full width in narrow popup and sidebar chats.
category: fix
dev: ChatView.css adds a `@container chat-view (max-width: 30rem)` rule setting `.chat-message` to max-width:100%, plus the mobile viewport rule bumped from 90% to 100%.

View File

@@ -361,8 +361,8 @@ Chat view provides project-scoped conversations with agents.
- Direct chat sessions can be renamed from the desktop conversation context menu and from the mobile session switcher; blank rename submissions clear the custom title so the default session label is shown again.
<!-- FNXC:ChatContextWindow 2026-06-27-00:00: Direct-chat docs must describe the desktop/tablet-only estimated token budget indicator and its intentional absence from mobile, narrow floating chat, and room headers. -->
- On desktop/tablet Direct chat, the thread header shows an estimated token count against the active model's known context window (for example `~12.3k / 200k`). It is hidden on mobile, narrow floating chat, rooms, and unknown-context-window models.
<!-- FNXC:ChatViewDocs 2026-06-23-11:48: Chat responsive docs need to distinguish the mobile all-bubble readability cap from the tablet main Chat assistant-only widening; Quick Chat remains governed by its narrow container so floating desktop hosts do not inherit the tablet measure. -->
- On mobile (`max-width: 768px`), chat bubbles are slightly wider in full Chat for improved readability while preserving header/composer gutters. On tablet-width main Chat containers, assistant/agent, streaming, and failure bubbles use a wider reading measure for long responses while user bubbles and narrow floating Quick Chat hosts stay bounded.
<!-- FNXC:ChatViewDocs 2026-06-28-14:52: Chat responsive docs must reflect that narrow chat hosts now key bubble width off the ChatView container, not just viewport media, so Quick Chat popups and the right dock on desktop viewports get the same full-width bubbles as phone Chat. -->
- In narrow Chat containers (including phone-width full Chat, narrow Quick Chat popups, and right-dock Chat), message bubbles use the full content width for improved readability. On tablet-width main Chat containers, assistant/agent, streaming, and failure bubbles keep the wider 88% reading measure, while wide desktop Chat keeps the standard 75% bubble cap.
- Full Chat tool-call summaries now use a denser mobile layout: grouped and single-call collapsed rows keep icon + label + status on one line (Quick Chat-style scanability) while expanded details remain unchanged.
<!-- FNXC:ChatAskQuestion 2026-06-17-16:35: Dashboard chat agents have a Fusion-native `fn_ask_question` tool, so the documented question-card behavior must cover both provider-native question tools and Fusion's first-party tool. -->
- Assistant question tool calls now render as a shared in-chat response card instead of a generic tool-call disclosure. The card recognizes provider-native question tools and Fusion's `fn_ask_question`, supports select, multi-select, text, and yes/no prompts, sends the formatted answer back into the same direct or room thread, and renders historical answered questions read-only.
@@ -427,7 +427,7 @@ Quick Chat is an optional fast, project-scoped assistant surface for conversatio
- FAB dragging uses pointer events with document-level move/up tracking and a 5px drag threshold so Android touch drags reposition reliably while short taps still open Quick Chat
- Quick Chat now mirrors full Chat tail behavior: if you scroll up, live updates stop auto-following and a **Latest** jump control appears until you jump back down.
- On mobile, Quick Chat re-anchors to the newest message whenever the panel is opened/reopened and when page visibility is restored, while still preserving the near-bottom gate so intentional scroll-away keeps **Latest** jump behavior.
- On mobile, Quick Chat bubbles are slightly wider while keeping compact tool-call summary layout and full-screen/safe-area behavior intact.
- On mobile and other narrow Quick Chat container widths, Quick Chat bubbles use the full content width while keeping compact tool-call summary layout and full-screen/safe-area behavior intact.
- On mobile, the fullscreen Quick Chat sheet follows soft-keyboard `visualViewport` height/offset samples directly, dedupes repeated identical samples, and smooths Android resize-content height-only changes so the sheet does not visibly step while the keyboard animates. iOS-style non-zero `offsetTop` samples still apply synchronously so transform alignment stays exact.
- On mobile, Quick Chat send reliability includes a delivery watchdog: if a queued message would otherwise stay stranded in the composer after a dropped or suspended stream, it is re-confirmed and delivered once no generation is in flight and no live stream is connected, so sends are not silently dropped.
- On mobile, Quick Chat sends exactly once per tap even when the browser emits paired pointer and touch events; a stop tap immediately after send is still honored.

View File

@@ -1034,6 +1034,16 @@ Tablet Chat View has enough message-pane width for assistant prose, markdown, to
}
}
/*
FNXC:ChatView 2026-06-28-14:47:
Narrow chat hosts need full-width bubbles for prose, code, tool output, failures, streams, and attachments in already-constrained columns. Key this to the ChatView container width, not the viewport, so Quick Chat popups and the right dock on desktop viewports match phone-width Chat View behavior.
*/
@container chat-view (max-width: 30rem) {
.chat-message {
max-width: 100%;
}
}
.chat-message-avatar {
display: flex;
align-items: center;
@@ -2239,7 +2249,7 @@ Queued-message banners stack above the composer input with a capped scroll area,
}
.chat-message {
max-width: 90%;
max-width: 100%;
}
.chat-message-failure-details summary,

View File

@@ -424,10 +424,10 @@ describe("ChatView CSS — failure bubble contracts", () => {
});
});
describe("ChatView CSS — tablet assistant bubble width", () => {
describe("ChatView CSS — responsive bubble width", () => {
const css = loadAllAppCss();
it("widens assistant, streaming, and failure bubbles on tablet containers while preserving user and mobile caps", async () => {
it("widens assistant, streaming, and failure bubbles on tablet containers while preserving desktop and mobile rules", async () => {
const baseMessageRule = css.match(/\.chat-message\s*\{([^}]*)\}/);
const userRule = css.match(/\.chat-message--user\s*\{([^}]*)\}/);
const tabletRule = css.match(
@@ -441,7 +441,21 @@ describe("ChatView CSS — tablet assistant bubble width", () => {
/\.chat-message--assistant,\s*\.chat-message--streaming,\s*\.chat-message--failure\s*\{[^}]*max-width:\s*88%/,
);
expect(tabletRule?.[1]).not.toMatch(/\.chat-message--user\s*\{[^}]*max-width/);
expect(css).toMatch(/@media\s*\(max-width:\s*768px\)[\s\S]*?\.chat-message\s*\{[^}]*max-width:\s*90%/);
expect(css).toMatch(/@media\s*\(max-width:\s*768px\)[\s\S]*?\.chat-message\s*\{[^}]*max-width:\s*100%/);
});
it("makes all chat message variants full-width in narrow chat-view containers without changing desktop or tablet caps", async () => {
const baseMessageRule = css.match(/\.chat-message\s*\{([^}]*)\}/);
const narrowRule = css.match(/@container\s+chat-view\s+\(max-width:\s*30rem\)\s*\{([\s\S]*?)\n\}/);
const tabletRule = css.match(
/@container\s+chat-view\s+\(min-width:\s*48\.0625rem\)\s+and\s+\(max-width:\s*64rem\)\s*\{([\s\S]*?)\n\}/,
);
expect(baseMessageRule?.[1]).toContain("max-width: 75%");
expect(narrowRule?.[1]).toMatch(/\.chat-message\s*\{[^}]*max-width:\s*100%/);
expect(tabletRule?.[1]).toMatch(
/\.chat-message--assistant,\s*\.chat-message--streaming,\s*\.chat-message--failure\s*\{[^}]*max-width:\s*88%/,
);
});
});

View File

@@ -1801,8 +1801,8 @@ describe("ChatView mobile CSS contract", () => {
expect(css).toMatch(/@media\s*\(max-width:\s*768px\)[\s\S]*?\.chat-thread--keyboard-active\s*\{[^}]*--vv-height/);
});
it("mobile widens chat bubbles for readability", async () => {
expect(css).toMatch(/@media\s*\(max-width:\s*768px\)[\s\S]*?\.chat-message\s*\{[^}]*max-width:\s*90%/);
it("mobile makes chat bubbles full-width for narrow-column readability", async () => {
expect(css).toMatch(/@media\s*\(max-width:\s*768px\)[\s\S]*?\.chat-message\s*\{[^}]*max-width:\s*100%/);
});
it("mobile keeps thread-header identity and render toggle inline", async () => {