diff --git a/frontend/src/components/ChatView/ChatInputBar.jsx b/frontend/src/components/ChatView/ChatInputBar.jsx index 2182f6914..c27a1ad0f 100644 --- a/frontend/src/components/ChatView/ChatInputBar.jsx +++ b/frontend/src/components/ChatView/ChatInputBar.jsx @@ -131,9 +131,20 @@ _touchMql?.addEventListener('change', (e) => { _isTouchPrimary = e.matches }) * * Send, Steer, and Stop are states of the same primary action. They * deliberately share the `primary` key so React preserves the 40px action - * target and swaps only its icon, label, handler, and semantic colour—there - * must be no empty/black replacement frame between any of them. Mic remains - * distinct because it is the idle input affordance rather than a turn action. */ + * target. PrimaryActionGlyph likewise preserves all three glyph layers: this + * lets transitions into Stop crossfade continuously instead of replacing the + * SVG in one frame. Send → Steer remains immediate. Mic stays distinct because + * it is the idle input affordance rather than a turn action. */ +function PrimaryActionGlyph({ action }) { + return ( + + ) +} + function PrimaryAction({ sending, listening, hasInput, hasUploading, offline, showSteer, steerReady, submissionBlocked, @@ -155,7 +166,7 @@ function PrimaryAction({ aria-busy={!steerReady} disabled={!steerReady} > - + ) } @@ -174,7 +185,7 @@ function PrimaryAction({ onClick={onStop} aria-label="Stop" > -