| 488 | if (!context) return |
| 489 | |
| 490 | const handleKeyDown = (e: KeyboardEvent) => { |
| 491 | const content = contentRef.current |
| 492 | if (!content) return |
| 493 | |
| 494 | const activeElement = document.activeElement |
| 495 | const isInputFocused = |
| 496 | activeElement instanceof HTMLInputElement || |
| 497 | activeElement instanceof HTMLTextAreaElement || |
| 498 | activeElement?.getAttribute('contenteditable') === 'true' |
| 499 | if (isInputFocused) return |
| 500 | |
| 501 | const items = content.querySelectorAll<HTMLElement>( |
| 502 | '[role="menuitem"]:not([aria-disabled="true"])' |
| 503 | ) |
| 504 | if (items.length === 0) return |
| 505 | |
| 506 | const currentIndex = context.selectedIndex |
| 507 | |
| 508 | switch (e.key) { |
| 509 | case 'ArrowDown': |
| 510 | e.preventDefault() |
| 511 | e.stopPropagation() |
| 512 | context.setKeyboardNav(true) |
| 513 | if (currentIndex < 0) { |
| 514 | context.setSelectedIndex(0) |
| 515 | } else { |
| 516 | context.setSelectedIndex(currentIndex < items.length - 1 ? currentIndex + 1 : 0) |
| 517 | } |
| 518 | break |
| 519 | case 'ArrowUp': |
| 520 | e.preventDefault() |
| 521 | e.stopPropagation() |
| 522 | context.setKeyboardNav(true) |
| 523 | if (currentIndex < 0) { |
| 524 | context.setSelectedIndex(items.length - 1) |
| 525 | } else { |
| 526 | context.setSelectedIndex(currentIndex > 0 ? currentIndex - 1 : items.length - 1) |
| 527 | } |
| 528 | break |
| 529 | case 'Enter': |
| 530 | case ' ': |
| 531 | if (currentIndex >= 0) { |
| 532 | e.preventDefault() |
| 533 | e.stopPropagation() |
| 534 | const selectedItem = items[currentIndex] |
| 535 | if (selectedItem) { |
| 536 | selectedItem.click() |
| 537 | } |
| 538 | } |
| 539 | break |
| 540 | } |
| 541 | } |
| 542 | |
| 543 | window.addEventListener('keydown', handleKeyDown, true) |
| 544 | return () => window.removeEventListener('keydown', handleKeyDown, true) |