function useKeyboardNav()

in src/SelectMenu/hooks/useKeyboardNav.js [4:88]


function useKeyboardNav(details, open, setOpen) {
  const handleKeyDown = useCallback(
    event => {
      const closeDetails = () => {
        setOpen(false)
        const summary = details.current.querySelector('summary')
        if (summary) summary.focus()
      }
      const openDetails = () => {
        setOpen(true)
      }
      const focusItem = next => {
        const options = Array.from(
          details.current.querySelectorAll(
            '[role^="menuitem"]:not([hidden]):not([disabled]):not([aria-disabled="true"])'
          )
        )
        const selected = document.activeElement
        const index = options.indexOf(selected)
        const found = next ? options[index + 1] : options[index - 1]
        const def = next ? options[0] : options[options.length - 1]
        return found || def
      }

      const isMenuItem = el => {
        const role = el.getAttribute('role')
        return role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio'
      }
      if (!(event instanceof KeyboardEvent)) return
      const isSummaryFocused = event.target instanceof Element && event.target.tagName === 'SUMMARY'
      switch (event.key) {
        case 'Escape':
          if (open) {
            closeDetails(details)
            event.preventDefault()
            event.stopPropagation()
          }
          break
        case 'ArrowDown':
          {
            if (isSummaryFocused && !open) {
              openDetails(details)
            }
            const target = focusItem(true)
            if (target) target.focus()
            event.preventDefault()
          }
          break
        case 'ArrowUp':
          {
            if (isSummaryFocused && !open) {
              openDetails()
            }
            const target = focusItem(false)
            if (target) target.focus()
            event.preventDefault()
          }
          break
        case ' ':
        case 'Enter':
          {
            const selected = document.activeElement
            if (selected && isMenuItem(selected) && selected.closest('details') === details) {
              event.preventDefault()
              event.stopPropagation()
              selected.click()
            }
          }
          break
        default:
      }
    },
    [details, open, setOpen]
  )

  useEffect(() => {
    const current = details.current
    if (!current) return

    current.addEventListener('keydown', handleKeyDown)
    return () => {
      current.removeEventListener('keydown', handleKeyDown)
    }
  }, [details, handleKeyDown])
}