feat: migrate composer popups to `Item` and add `ItemMeta` `truncate`
Proposed changes (including videos or screenshots)
ARCH-2496
Adds truncate to ItemMeta, and renders the composer popups with Item.
It also makes the composer popups behave the same as menus when moving through them with a keyboard or a pointer. One row is active at a time, the pointer and the arrow keys both move it, and the focus ring shows while the keyboard drives the list:
| Opens with an active row | Pointer moves the active row | Focus ring | |
|---|---|---|---|
| Menu | the first one | yes | keyboard only |
| Composer popups | the first one, which Enter and Tab pick | yes | while typing or using the arrow keys |
The composer rings its first row on open because the active row's background alone has a 1.15:1 contrast against the popup in the dark theme, below the 3:1 that WCAG 1.4.11 asks for a state indicator.
Screenshots
Captured against open.rocket.chat with yarn dev:next, develop above and this PR below.
Composer popup on open: the first row, which Enter and Tab pick, shows its ring
Composer popup after the arrow keys and then the pointer: develop highlights two rows, this PR only the one under the pointer
Composer popup in forced colors: develop shows no indicator on the active row, this PR shows its outline
Fuselage
- Adds a
truncateprop toItemMeta. With it, long trailing meta text truncates with an ellipsis instead of pushing the title. - The
Itemfocus ring shows in forced colors (Windows high contrast), which drop the box-shadow it is drawn with.
Rocket.Chat
- The composer's mention, room, emoji, canned response and slash command popups are listboxes of
Itemrows. Slash command parameters truncate withItemMeta truncate, and slash command preview rows show keyboard focus withfocusVisible. - The composer popups keep one active row: the row under the pointer becomes the one Enter and Tab pick, and the message field names the listbox it controls with
aria-controlsandaria-autocomplete.
Issue(s)
Replaces RocketChat/fuselage#2311, and takes over the composer popup part of #42520.
Steps to test or reproduce
- In a room's composer, type
@,#,:and/, pick a canned response in an omnichannel room, and use a slash command with a preview. Move through the popup with the arrow keys and with the pointer: one row is highlighted at a time, and Enter picks that row. - Check it with a screen reader, and the focus ring with Windows high contrast or Chrome's forced colors emulation.
Further comments
Based on develop. #42819 (sidebar and side panel) is stacked on this PR and reuses useActiveDescendant for the room search, so this one merges first.
Commits are ordered so the fix and the enabling refactor sit below the feature and can be extracted:
regression(fuselage): theItemfocus ring in forced colorsrefactor:useActiveDescendant, the shared state of listboxes driven from a combobox- the
ItemMeta truncateand composer popup commits fix: the composer popups keep one active row (needs the composerItemrows from step 3)
Part of the Item migration, split by area:
- #42818: options, selects, menus and member lists (merged)
- this PR: composer popups,
ItemMeta truncate, and keyboard and pointer behaviour of the composer popups (merge first) - #42819: sidebar, side panel, and keyboard and pointer behaviour of the room search (stacked on this PR)
- #42832: lists that only use
Item(independent)
The popup changes from role=menu to listbox, so the composer e2e locators find rows as listbox options.
Summary by CodeRabbit
- Accessibility
- Composer suggestions are presented as labeled option lists, with screen-reader associations and disabled states announced.
- Keyboard navigation displays a focus indicator, while pointer movement updates the active suggestion.
- Usability
- Enter and Tab no longer select disabled suggestions.
- Long slash-command parameters and descriptions are truncated to keep command names visible.