From 0e43a18bc6fbf2023e0070f77d99b738673ffc0b Mon Sep 17 00:00:00 2001 From: Rebeka Dekany <50901361+rebekadekany@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:15:08 +0200 Subject: [PATCH] Merge pull request #19881 from overleaf/rd-filetree-context-menu [web] Context menu should receive focus in the filetree on keyboard navigation GitOrigin-RevId: aeec3713b32792bd5aef1756929a4fc893f30274 --- .../components/file-tree-context-menu.tsx | 38 +++++++++++++++++-- .../file-tree-item-menu-items.jsx | 2 +- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx index 3afa3ece7b..f52a33de9e 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useEffect, useRef } from 'react' import ReactDOM from 'react-dom' import { Dropdown } from 'react-bootstrap' import { useEditorContext } from '../../../shared/context/editor-context' @@ -9,12 +9,33 @@ import FileTreeItemMenuItems from './file-tree-item/file-tree-item-menu-items' function FileTreeContextMenu() { const { permissionsLevel } = useEditorContext() const { contextMenuCoords, setContextMenuCoords } = useFileTreeMainContext() + const toggleButtonRef = useRef(null) - if (permissionsLevel === 'readOnly' || !contextMenuCoords) return null + useEffect(() => { + if (contextMenuCoords) { + toggleButtonRef.current = document.querySelector( + '.entity-menu-toggle' + ) as HTMLButtonElement | null + focusContextMenu() + } + }, [contextMenuCoords]) + + if (!contextMenuCoords || permissionsLevel === 'readOnly') return null + + // A11y - Move the focus to the context menu when it opens + function focusContextMenu() { + const contextMenu = document.querySelector( + '[aria-labelledby="dropdown-file-tree-context-menu"]' + ) as HTMLElement | null + contextMenu?.focus() + } function close() { - // reset context menu setContextMenuCoords(null) + if (toggleButtonRef.current) { + // A11y - Move the focus back to the toggle button when the context menu closes by pressing the Esc key + toggleButtonRef.current.focus() + } } function handleToggle(wantOpen: boolean) { @@ -25,6 +46,14 @@ function FileTreeContextMenu() { handleToggle(false) } + // A11y - Close the context menu when the user presses the Tab key + // Focus should move to the next element in the filetree + function handleKeyDown(event: React.KeyboardEvent) { + if (event.key === 'Tab') { + close() + } + } + return ReactDOM.createPortal( - + , diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu-items.jsx b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu-items.jsx index 839707aeb9..321d973f4d 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu-items.jsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu-items.jsx @@ -56,7 +56,7 @@ function FileTreeItemMenuItems() { ) : null} {canCreate ? ( <> - +
  • {t('new_file')} {t('new_folder')} {t('upload')}