Repository navigation
UI kit: shared Menu component for context and dropdown menus; ratchets on raw <button> and hand-built dialogs #914
Copy link
Copy link
Open
Labels
accessibilityBarrier affecting people with disabilitiesBarrier affecting people with disabilitiesfrontendFrontend (React/TypeScript)Frontend (React/TypeScript)
Milestone
Description
Goal
Context and dropdown menus share one accessible implementation (role menu, arrow keys, Escape, placement), and new raw <button> elements or hand-built modal dialogs outside the UI kit only appear with a reason.
Context
- Menus are implemented locally:
FileEntryMenu(components/FileBrowserPanel.tsx:2864),ColumnsMenu(:3050),DirectoryMenu(~:3463), andcomponents/NewSessionMenu.tsx. Only the placement hookhooks/useMenuPlacement.ts(+menuPlacement.ts) is shared (3 users). - 72 raw
<button>insrc/componentsproduction code (27 inFileBrowserPanel.tsx, 6NarrowHeaderNav.tsx, 5ChatPanel.tsx, 4TerminalKeyRow.tsx, …) next to 229<Button>. - Modals outside
components/ui/DialogFrame.tsx:HostKeyDialog.tsx,SettingsScreen.tsx,NarrowHeaderNav.tsx(each with its ownuseDialogFocusTrap),AppHeader.tsx(fixed inset-0overlay), and the server form's key-import prompt (moved toDialogFrameby Server form: the key-import prompt uses DialogFrame (focus trap, Escape, labelled title) #852). - Paths are relative to
apps/smart-ssh-community/frontend/src/; line numbers will have moved if the file browser was already split into sub-components.
Requirements
components/ui/Menu.tsx:Menu(positioned at a point or anchored to an element, usesuseMenuPlacement),MenuItem(button withrole="menuitem", optional icon, shortcut hint,disabled,danger),MenuSeparator. Keyboard: arrow up/down/Home/End move focus, Enter/Space activate, Escape closes and returns focus to the opener, Tab closes. Click outside closes. Export fromcomponents/ui/index.ts; document indocs/ui-guidelines.md.- Move the four menus onto it; items, texts and actions unchanged.
- Dialog guard: production
.tsxfiles may contain<dialogorfixed inset-0only incomponents/ui/andcomponents/ModalBackdrop.tsx, plus an allowlist (file + one-line reason) that may only shrink. - Guard test: count raw
<buttonper production.tsxfile outsidecomponents/ui/; compare with a checked-in JSON (file → count); a count may only fall; a new file with raw buttons needs an entry with a reason. Error message points toButton/MenuItem.
Acceptance Criteria
- Menu tests: roles, arrow-key navigation, Escape returns focus to the opener, disabled items are skipped, click outside closes.
- The four menus use
Menu; their existing tests pass (selector updates allowed). - Raw
<button>count inFileBrowserPanel.tsxandNewSessionMenu.tsxdrops (menu items replaced); the ratchet test passes and fails when a raw button is added to a fixture. - The dialog guard passes and fails for a fixture with
<dialogoutside the allowed places. - Playwright accessibility spec passes;
npm run lint, type-check,npm testpass.
Technical Notes
- Frontend only. If the file browser decomposition has already moved the menus into
components/fileBrowser/, migrate them there.
Spec impact: none
Related Work
- Blocked by Theming: migrate file browser and server form to colour tokens #807, Theming: migrate server list, sessions and terminal to colour tokens #808 (token migration of these files), File browser: move the sub-components out of FileBrowserPanel.tsx into components/fileBrowser/ #819 (file browser sub-components moved to
components/fileBrowser/) and Server form: the key-import prompt uses DialogFrame (focus trap, Escape, labelled title) #852 (key-import prompt onDialogFrame, so it is not on the dialog allowlist).
Metadata
Metadata
Assignees
Labels
accessibilityBarrier affecting people with disabilitiesBarrier affecting people with disabilitiesfrontendFrontend (React/TypeScript)Frontend (React/TypeScript)
Type
Fields
Priority
P3 - Low
Activity
5 remaining items