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*\}/,