From 382a4d5d05f784a934d4e3edbc825d2d153b960d Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sun, 12 Jul 2026 23:02:46 -0700 Subject: [PATCH] FN-7917: center chat composer attach/model icons with input box Centers the Chat composer's attach and model/thinking icon buttons with the single-line message input across desktop, tablet, and mobile, while keeping them bottom-aligned when the textarea grows multi-line. - Size .chat-attach-btn, .chat-thinking-level-root, and .chat-thinking-btn to --chat-input-control-size (matching the send button/textarea min-height) instead of the old calc(var(--space-lg) * 2) / * 2.25) sizing - Replace the separate mobile touch-target overrides for .chat-attach-btn and .chat-thinking-btn with a shared rule using the same --chat-input-control-size sizing - Add a regression test asserting the attach/thinking controls use --chat-input-control-size and align-self: flex-end, and no longer use the old calc()-based sizing - Add a patch changeset for @runfusion/fusion documenting the composer icon centering fix Files changed: .changeset/chat-composer-icon-centering.md | 7 +++++ packages/dashboard/app/components/ChatView.css | 30 ++++++++++++---------- .../ChatView.chat-input-autosize.test.tsx | 28 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 13 deletions(-) Fusion-Task-Id: FN-7917 Fusion-Task-Lineage: aba1d5ea-21ee-4b27-90f2-11aca7c4a5fa Co-authored-by: Fusion (runfusion.ai) --- .changeset/chat-composer-icon-centering.md | 7 +++++ .../dashboard/app/components/ChatView.css | 30 +++++++++++-------- .../ChatView.chat-input-autosize.test.tsx | 28 +++++++++++++++++ 3 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 .changeset/chat-composer-icon-centering.md diff --git a/.changeset/chat-composer-icon-centering.md b/.changeset/chat-composer-icon-centering.md new file mode 100644 index 0000000000..6df2cc628e --- /dev/null +++ b/.changeset/chat-composer-icon-centering.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Center the Chat composer attach and model icons with the message input box. +category: fix +dev: ChatView.css sizes .chat-attach-btn and .chat-thinking-level-root to --chat-input-control-size so they center with the single-line input across desktop/tablet/mobile while staying bottom-aligned when multi-line (FN-7917). diff --git a/packages/dashboard/app/components/ChatView.css b/packages/dashboard/app/components/ChatView.css index 7583274c63..e3d5c0a4d2 100644 --- a/packages/dashboard/app/components/ChatView.css +++ b/packages/dashboard/app/components/ChatView.css @@ -1967,9 +1967,14 @@ CLI-agent sessions, or while streaming) — see StandardChatSurface.tsx `showEdi transform: scale(0.97); } +/* +FNXC:Chat-ComposerAlignment 2026-07-12-10:25: +Composer attach + model/thinking icon controls must be vertically centered with the single-line text input box on all surfaces (desktop/tablet/mobile). Match their block-size to --chat-input-control-size (== send button == textarea min-height) so align-self: flex-end yields center alignment when single-line and keeps them at the row bottom when the textarea grows multi-line. (FN-7917) +*/ .chat-attach-btn { - min-width: calc(var(--space-lg) * 2); - min-height: calc(var(--space-lg) * 2); + min-inline-size: var(--chat-input-control-size); + min-block-size: var(--chat-input-control-size); + block-size: var(--chat-input-control-size); align-self: flex-end; } @@ -1985,12 +1990,15 @@ FN-7908 keeps model/agent retargeting inside the same brain popup. The widened p */ .chat-thinking-level-root { position: relative; + min-block-size: var(--chat-input-control-size); + block-size: var(--chat-input-control-size); align-self: flex-end; } .chat-thinking-btn { - min-width: calc(var(--space-lg) * 2); - min-height: calc(var(--space-lg) * 2); + min-inline-size: var(--chat-input-control-size); + min-block-size: var(--chat-input-control-size); + block-size: var(--chat-input-control-size); } .chat-thinking-btn--active { @@ -2520,16 +2528,12 @@ Queued-message banners stack above the composer input with a capped scroll area, margin-left: auto; } - /* primary touch targets per AGENTS.md convention */ - .chat-attach-btn { - min-width: calc(var(--space-lg) * 2.25); - min-height: calc(var(--space-lg) * 2.25); - } - - /* FN-7898: mirror the attach button's mobile touch-target bump. */ + /* primary touch targets per AGENTS.md convention; FN-7917 keeps the icon controls in parity with the send/input control size on mobile too. */ + .chat-attach-btn, .chat-thinking-btn { - min-width: calc(var(--space-lg) * 2.25); - min-height: calc(var(--space-lg) * 2.25); + min-inline-size: var(--chat-input-control-size); + min-block-size: var(--chat-input-control-size); + block-size: var(--chat-input-control-size); } /* diff --git a/packages/dashboard/app/components/__tests__/ChatView.chat-input-autosize.test.tsx b/packages/dashboard/app/components/__tests__/ChatView.chat-input-autosize.test.tsx index 3445bec171..49336a465d 100644 --- a/packages/dashboard/app/components/__tests__/ChatView.chat-input-autosize.test.tsx +++ b/packages/dashboard/app/components/__tests__/ChatView.chat-input-autosize.test.tsx @@ -33,6 +33,34 @@ describe("ChatView chat input autosize", () => { expect(stopRule?.[0]).toContain("min-height: var(--chat-input-control-size)"); }); + it("centers attach and thinking controls with the single-line input while preserving bottom row alignment", () => { + const attachRule = chatViewCss.match(/\.chat-attach-btn\s*\{[^}]*\}/); + const thinkingRootRule = chatViewCss.match(/\.chat-thinking-level-root\s*\{[^}]*\}/); + const thinkingButtonRule = chatViewCss.match(/\.chat-thinking-btn\s*\{[^}]*\}/); + const mobileRule = chatViewCss.match( + /\/\* primary touch targets[\s\S]*?\.chat-attach-btn,\s*\.chat-thinking-btn\s*\{[^}]*\}/, + ); + + expect(attachRule).not.toBeNull(); + expect(thinkingRootRule).not.toBeNull(); + expect(thinkingButtonRule).not.toBeNull(); + expect(mobileRule).not.toBeNull(); + + expect(attachRule?.[0]).toContain("min-block-size: var(--chat-input-control-size)"); + expect(attachRule?.[0]).toContain("block-size: var(--chat-input-control-size)"); + expect(attachRule?.[0]).toContain("align-self: flex-end"); + expect(thinkingRootRule?.[0]).toContain("min-block-size: var(--chat-input-control-size)"); + expect(thinkingRootRule?.[0]).toContain("block-size: var(--chat-input-control-size)"); + expect(thinkingRootRule?.[0]).toContain("align-self: flex-end"); + expect(thinkingButtonRule?.[0]).toContain("min-block-size: var(--chat-input-control-size)"); + expect(thinkingButtonRule?.[0]).toContain("block-size: var(--chat-input-control-size)"); + expect(mobileRule?.[0]).toContain("min-block-size: var(--chat-input-control-size)"); + expect(mobileRule?.[0]).toContain("block-size: var(--chat-input-control-size)"); + expect(attachRule?.[0]).not.toContain("min-height: calc(var(--space-lg) * 2)"); + expect(thinkingButtonRule?.[0]).not.toContain("min-height: calc(var(--space-lg) * 2)"); + expect(mobileRule?.[0]).not.toContain("calc(var(--space-lg) * 2.25)"); + }); + it("caps textarea max-height at 200px on tablet viewports", () => { const tabletRule = chatViewCss.match( /@media \(min-width: 769px\) and \(max-width: 1024px\)\s*\{\s*\.chat-input-textarea\s*\{[^}]*\}\s*\}/,