Skip to content

Replace menu shortcuts with spatial arrow-key navigation#114

Draft
developit wants to merge 1 commit intomainfrom
claude/keyboard-navigation-arrows-AbnVw
Draft

Replace menu shortcuts with spatial arrow-key navigation#114
developit wants to merge 1 commit intomainfrom
claude/keyboard-navigation-arrows-AbnVw

Conversation

@developit
Copy link
Copy Markdown
Owner

Summary

Replaced the simple up/down arrow navigation system with a more sophisticated spatial navigation implementation that uses ray-casting to find focusable elements in any direction (up, down, left, right).

Key Changes

  • Rewrote arrow key handler: Replaced handleMenuShortcutsKeydown() with handleArrowKey() that implements spatial navigation via elementFromPoint() ray-casting
  • Added directional support: Extended from vertical-only (up/down) to full 2D navigation (left, right, up, down)
  • Improved focus detection: Now properly detects and respects native arrow key behavior in inputs, textareas, and contentEditable elements
  • Simplified initialization: Removed installMenuShortcuts() function and its guard flag; arrow key handler now installs automatically on module load
  • Removed redundant calls: Eliminated installMenuShortcuts() calls from ComboboxBase and DropdownMenu components since initialization is now automatic

Implementation Details

  • Ray-casting algorithm starts from the focused element's edge in the arrow direction and steps through the viewport in 8-pixel increments
  • Respects dialog boundaries when navigating pseudo-focused elements (elements with [selected] attribute)
  • Handles both real focus (standard elements) and pseudo-focus (combobox-style virtual cursor)
  • Skips navigation for elements with disabled attribute and respects viewport boundaries
  • Uses scrollIntoView() for pseudo-focused elements to ensure visibility

https://claude.ai/code/session_01TpntAcHRsAf2hJr2WzyFVD

Replaces installMenuShortcuts with a single auto-installed handler that
ray-casts from the focused element's edge in the arrow direction using
document.elementFromPoint(). The DOM layout is the navigation graph, so
one ~50-line handler covers every kinu widget (dropdowns, tabs, menubar,
tree, carousel, dialog buttons, etc.) without per-component wiring.

An adjacent open dialog[k] with a [k][selected] child flips on
pseudo-focus — the virtual cursor moves [selected] instead of real focus
— which is how Combobox keeps the caret in the input while arrows walk
options. Handler self-scopes to kinu widgets and skips elements where
arrows have native meaning (text inputs, select, slider, radio, etc).
@netlify
Copy link
Copy Markdown

netlify bot commented Apr 14, 2026

Deploy Preview for kinu-sh ready!

Name Link
🔨 Latest commit 4aebfe5
🔍 Latest deploy log https://app.netlify.com/projects/kinu-sh/deploys/69dde5f31372d30007808149
😎 Deploy Preview https://deploy-preview-114--kinu-sh.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

Size Change: +1.27 kB (+4.01%)

Total Size: 32.8 kB

📦 View Changed
Filename Size Change
benchmarks/size/.tmp/few-components/bundle.js 1.14 kB +737 B (+181.98%) 🆘
benchmarks/size/.tmp/nearly-all-components/bundle.js 3.5 kB +272 B (+8.44%) 🔍
dist/index.js 5.9 kB +257 B (+4.56%) 🔍
ℹ️ View Unchanged
Filename Size
benchmarks/size/.tmp/few-components/bundle.css 2.85 kB
benchmarks/size/.tmp/nearly-all-components/bundle.css 8.79 kB
benchmarks/size/.tmp/one-component/bundle.css 1.43 kB
benchmarks/size/.tmp/one-component/bundle.js 333 B
dist/index.css 8.9 kB

compressed-size-action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants