file-tree-context-menu.tsx 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import React, { useEffect, useRef } from 'react'
  2. import ReactDOM from 'react-dom'
  3. import {
  4. Dropdown,
  5. DropdownMenu,
  6. } from '@/features/ui/components/bootstrap-5/dropdown-menu'
  7. import { useFileTreeData } from '@/shared/context/file-tree-data-context'
  8. import { useFileTreeMainContext } from '../contexts/file-tree-main'
  9. import FileTreeItemMenuItems from './file-tree-item/file-tree-item-menu-items'
  10. function FileTreeContextMenu() {
  11. const { fileTreeReadOnly } = useFileTreeData()
  12. const { contextMenuCoords, setContextMenuCoords } = useFileTreeMainContext()
  13. const toggleButtonRef = useRef<HTMLButtonElement | null>(null)
  14. useEffect(() => {
  15. if (contextMenuCoords) {
  16. toggleButtonRef.current = document.querySelector(
  17. '.entity-menu-toggle'
  18. ) as HTMLButtonElement | null
  19. }
  20. }, [contextMenuCoords])
  21. if (!contextMenuCoords || fileTreeReadOnly) return null
  22. function close() {
  23. setContextMenuCoords(null)
  24. if (toggleButtonRef.current) {
  25. // A11y - Move the focus back to the toggle button when the context menu closes by pressing the Esc key
  26. toggleButtonRef.current.focus()
  27. }
  28. }
  29. function handleToggle(wantOpen: boolean) {
  30. if (!wantOpen) close()
  31. }
  32. // A11y - Close the context menu when the user presses the Tab key
  33. // Focus should move to the next element in the filetree
  34. function handleKeyDown(event: React.KeyboardEvent<Element>) {
  35. if (event.key === 'Tab') {
  36. close()
  37. }
  38. }
  39. return ReactDOM.createPortal(
  40. <div style={contextMenuCoords} className="context-menu">
  41. <Dropdown
  42. show
  43. drop={
  44. document.body.offsetHeight / contextMenuCoords.top < 2 &&
  45. document.body.offsetHeight - contextMenuCoords.top < 250
  46. ? 'up'
  47. : 'down'
  48. }
  49. focusFirstItemOnShow // A11y - Focus the first item in the context menu when it opens since the menu is rendered at the root level
  50. onKeyDown={handleKeyDown}
  51. onToggle={handleToggle}
  52. >
  53. <DropdownMenu
  54. className="dropdown-menu-sm-width"
  55. id="dropdown-file-tree-context-menu"
  56. >
  57. <FileTreeItemMenuItems />
  58. </DropdownMenu>
  59. </Dropdown>
  60. </div>,
  61. document.body
  62. )
  63. }
  64. export default FileTreeContextMenu