diff --git a/client/src/components/Chat/Input/Files/FileContainer.tsx b/client/src/components/Chat/Input/Files/FileContainer.tsx index e914be08d2..3f47b0b545 100644 --- a/client/src/components/Chat/Input/Files/FileContainer.tsx +++ b/client/src/components/Chat/Input/Files/FileContainer.tsx @@ -95,8 +95,10 @@ const FileContainer = ({ * subtitle it would otherwise read as a description rather than a control. The * hit area is the label and nothing more: `inline-block` keeps it off the rest * of the row, and `leading-4` keeps it inside its 20px line so the chip's own - * center still opens the editor. */ - 'pointer-events-auto relative z-10 inline-block max-w-full truncate rounded text-left align-middle leading-4 text-text-secondary underline underline-offset-2 hover:text-text-primary', + * center still opens the editor. The colour shift answers focus as well as + * hover: the ring already announces focus, but leaving the two input modes + * with different feedback is a difference with no reason behind it. */ + 'pointer-events-auto relative z-10 inline-block max-w-full truncate rounded text-left align-middle leading-4 text-text-secondary underline underline-offset-2 hover:text-text-primary focus-visible:text-text-primary', focusRing, )} > diff --git a/client/src/components/Chat/Input/Files/__tests__/FileContainer.spec.tsx b/client/src/components/Chat/Input/Files/__tests__/FileContainer.spec.tsx index 6c44251613..e094bb2742 100644 --- a/client/src/components/Chat/Input/Files/__tests__/FileContainer.spec.tsx +++ b/client/src/components/Chat/Input/Files/__tests__/FileContainer.spec.tsx @@ -77,12 +77,17 @@ describe('FileContainer subtitle action', () => { /** The affordance used to live behind a `group-hover` swap, which left the chip reading as * an inert "Plain Text" until pointed at — so nobody found it, and touch had no pointer to - * find it with. Nothing about the label may be conditional on hover or focus again. */ + * find it with. Nothing about the label may be conditional on hover or focus again. + * + * Asserted on class tokens deliberately, brittle as that is. jsdom loads no stylesheet, so + * a hover gate has no effect on the DOM here and a presence check cannot see one: the swap + * this replaced kept BOTH labels mounted, which is why the spec it replaced asserted they + * were both in the document at once. Only the tokens distinguish the two markups. */ const control = screen.getByRole('button', { name: 'Move back into message' }); expect(control.className).not.toContain('group-hover'); expect(control.className).not.toContain('group-focus-within'); expect(control.className).not.toContain('hover:none'); - expect(control.textContent).toBe('Move back into message'); + expect(control).toHaveTextContent('Move back into message'); }); it('names the subtitle control from its own visible label', () => { @@ -164,6 +169,18 @@ describe('FileContainer subtitle action', () => { expect(control.className).not.toContain('hover:underline'); }); + it('gives keyboard focus the same feedback the pointer gets', () => { + render( + , + ); + + /** The focus ring already announces focus, so this is parity rather than a missing + * indicator: whatever the colour shift signals to a pointer, it signals to a keyboard. */ + const control = screen.getByRole('button', { name: 'Move back into message' }); + expect(control.className).toContain('hover:text-text-primary'); + expect(control.className).toContain('focus-visible:text-text-primary'); + }); + it('leaves the plain subtitle alone when no action is offered', () => { render();