FN-7634: widen Planner Chat stop button to match send button
Fix the Planner Chat composer's streaming Stop button rendering narrower than the idle Send button by giving both variants a shared width floor. - Declare a locally-scoped --chat-input-control-size on .task-planner-chat-composer (same formula as ChatView.css's .chat-input-row so the shared .chat-input-send/.chat-input-stop classes no longer read an undefined custom property and fall back to width: auto. - Add a min-inline-size floor bound to that property on .task-planner-chat-send (present on both send and stop variants) so neither button renders narrower than the other on desktop. - Add a regression test asserting the desktop control-size floor, the pre-existing mobile square sizing, and the FN-7594 stop-icon visibility contract. - Add a changeset documenting the fix as a patch release. Files changed: .changeset/fn-7634-planner-stop-button-width.md | 7 +++++ .../app/components/TaskPlannerChatTab.css | 8 ++++++ .../__tests__/TaskPlannerChatTab.test.tsx | 33 ++++++++++++++++++++++ 3 files changed, 48 insertions(+) EOF ) Fusion-Task-Id: FN-7634 Fusion-Task-Lineage: e73c836f-3c2d-4871-ac93-fdf5e52de5f6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-7634-planner-stop-button-width.md
Normal file
7
.changeset/fn-7634-planner-stop-button-width.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Fix the task-detail Planner Chat stop button rendering narrower than its send button.
|
||||
category: fix
|
||||
dev: `TaskPlannerChatTab.css` now declares a locally-scoped `--chat-input-control-size` on `.task-planner-chat-composer` (same formula as `ChatView.css`'s `.chat-input-row`) and applies it as a `min-inline-size` floor on `.task-planner-chat-send`, so the shared `.chat-input-send`/`.chat-input-stop` classes (which previously read an undefined custom property inside the Planner composer and fell back to `width: auto`) never render the streaming Stop button narrower than the idle Send button on desktop or mobile.
|
||||
@@ -192,8 +192,14 @@ Planner Chat must keep visual height parity with Activity chat: desktop textarea
|
||||
|
||||
FNXC:TaskDetailPlannerChat 2026-07-01-23:54:
|
||||
Mobile Planner Chat should match regular task chat: keep the composer as a single input row with a one-line textarea and a square send affordance on the right instead of stacking the labeled button below the input.
|
||||
|
||||
FNXC:TaskDetailPlannerChat 2026-07-07-00:00:
|
||||
The Planner Chat streaming Stop button must occupy the same width footprint as the Send button it replaces (no shift/shrink on swap) and mirror the regular Chat view's stop-button sizing (`.chat-input-row`'s `--chat-input-control-size` in ChatView.css). The shared `.chat-input-send` / `.chat-input-stop` classes read that custom property from `.chat-input-row`, which the Planner composer never renders inside of, so the property was undefined here and `width` fell back to `auto`, sizing each button from its own content only. Declare the same control-size formula scoped to `.task-planner-chat-composer` and give `.task-planner-chat-send` (present on both the send and stop button variants) a matching `min-inline-size` floor so neither button can render narrower than the other on desktop, without touching ChatView.css's own token.
|
||||
*/
|
||||
.task-planner-chat-composer {
|
||||
/* FN-7634: same formula as ChatView.css's `.chat-input-row { --chat-input-control-size: … }` so the Planner stop/send buttons share the regular Chat view's control-size floor. */
|
||||
--chat-input-control-size: calc(var(--space-lg) * 2.5);
|
||||
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
flex-wrap: wrap;
|
||||
@@ -215,6 +221,8 @@ Mobile Planner Chat should match regular task chat: keep the composer as a singl
|
||||
.task-planner-chat-send {
|
||||
flex: 0 0 auto;
|
||||
min-block-size: calc(var(--space-2xl) + var(--space-sm));
|
||||
/* FN-7634: floor both the Send and Stop button variants (both carry this class) at the same width so the streaming swap never narrows or widens the control. */
|
||||
min-inline-size: var(--chat-input-control-size);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
@@ -714,6 +714,39 @@ describe("TaskPlannerChatTab", () => {
|
||||
expect(stopIcon).toHaveClass("chat-input-stop-icon");
|
||||
});
|
||||
|
||||
it("keeps the planner stop button width in parity with the send button on desktop and mobile (FN-7634)", () => {
|
||||
// Desktop: both `.chat-input-send` and `.chat-input-stop` (from ChatView.css) read
|
||||
// `width: var(--chat-input-control-size)`, which is only declared inside `.chat-input-row`.
|
||||
// The Planner composer must declare that same custom property itself so the value never
|
||||
// resolves to `auto`, and must give the shared `.task-planner-chat-send` class (present on
|
||||
// both the send and stop button variants) a `min-inline-size` floor bound to it — otherwise
|
||||
// the streaming Stop button can render narrower than the idle Send button.
|
||||
expect(taskPlannerChatCss).toMatch(/\.task-planner-chat-composer\s*\{[\s\S]*?--chat-input-control-size:\s*calc\(var\(--space-lg\)\s*\*\s*2\.5\);/);
|
||||
|
||||
// The base (non-mobile) `.task-planner-chat-send` rule is the first one in source order,
|
||||
// before the `@media (max-width: 768px)` block redeclares it for mobile.
|
||||
const mediaQueryStart = taskPlannerChatCss.indexOf("@media (max-width: 768px)");
|
||||
const desktopCss = mediaQueryStart >= 0 ? taskPlannerChatCss.slice(0, mediaQueryStart) : taskPlannerChatCss;
|
||||
const desktopSendRule = desktopCss.match(/\.task-planner-chat-send\s*\{[^}]*\}/)?.[0] ?? "";
|
||||
// The desktop rule must bind the same control-size custom property as its floor so the
|
||||
// Send button (idle) and Stop button (streaming) — both of which carry this class — never
|
||||
// differ in width footprint.
|
||||
expect(desktopSendRule).toMatch(/min-inline-size:\s*var\(--chat-input-control-size\)/);
|
||||
|
||||
// Mobile keeps its pre-existing explicit square sizing, which already applies identically
|
||||
// to both the send and stop variants via the shared `.task-planner-chat-send` class.
|
||||
const mobileSendRule = taskPlannerChatCss
|
||||
.slice(mediaQueryStart)
|
||||
.match(/\.task-planner-chat-send\s*\{[^}]*\}/)?.[0] ?? "";
|
||||
expect(mobileSendRule).toMatch(/inline-size:\s*calc\(var\(--space-2xl\)\s*\+\s*var\(--space-lg\)\)/);
|
||||
expect(mobileSendRule).toMatch(/min-inline-size:\s*calc\(var\(--space-2xl\)\s*\+\s*var\(--space-lg\)\)/);
|
||||
|
||||
// Guard the FN-7594-era contract that the stop icon span stays visible on mobile even
|
||||
// though other text-label spans are visually hidden.
|
||||
const mobileTextHideRule = taskPlannerChatCss.match(/@media \(max-width: 768px\)[\s\S]*?\.task-planner-chat-send[^{}]*\{[^}]*clip:[^}]*\}/)?.[0] ?? "";
|
||||
expect(mobileTextHideRule).toMatch(/span:not\(\.chat-input-stop-icon\)/);
|
||||
});
|
||||
|
||||
it("renders live and stored thinking output through the standard chat surface", async () => {
|
||||
const user = userEvent.setup();
|
||||
mockFetchChatMessages.mockResolvedValueOnce({
|
||||
|
||||
Reference in New Issue
Block a user