Add nextFocusResolver to override default behavior#231
Merged
Conversation
🦋 Changeset detectedLatest commit: c6423e5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
asgvard
reviewed
Apr 27, 2026
…NavigationService for custom navigation handling
xavi160
force-pushed
the
navigation-strategy
branch
from
April 28, 2026 06:46
84d11bd to
5e77589
Compare
xavi160
marked this pull request as ready for review
April 28, 2026 07:20
predikament
approved these changes
Apr 28, 2026
asgvard
reviewed
Apr 28, 2026
Co-authored-by: Dmitriy Bryokhin <2877657+asgvard@users.noreply.github.com>
predikament
approved these changes
Apr 28, 2026
asgvard
approved these changes
Apr 28, 2026
xavi160
added a commit
that referenced
this pull request
Jun 18, 2026
* feat: add navigationStrategy to FocusableComponent and update SpatialNavigationService for custom navigation handling * refactor: rename navigationStrategy to nextFocusResolver * Create hot-falcons-begin.md * fix: add warning for invalid component in nextFocusResolver to prevent lost focus * Update packages/core/src/SpatialNavigation.ts Co-authored-by: Dmitriy Bryokhin <2877657+asgvard@users.noreply.github.com> --------- Co-authored-by: Dmitriy Bryokhin <2877657+asgvard@users.noreply.github.com>
xavi160
added a commit
that referenced
this pull request
Jun 30, 2026
* Migrate to async node measurement (#212) * chore: add test step in prs - Fixed jest setup to work with lodash-es using babel * feat: measuring layout is now async * refactor: rename layout adapter constants and introduce getBoundingClientRectAdapter * chore: add changeset * docs: update SpatialNavigation and related guides to reflect deprecation of useGetBoundingClientRect and introduce layoutAdapter for improved layout measurement * fix: replace unused layoutUpdate with layoutUpdatedAt timestamp to avoid unnecessary layout updates * feat: implement Scheduler class * fix: await smartNavigate in SpatialNavigationService to ensure proper asynchronous behavior * refactor: setFocus async * fix: handle undefined currentTask in Scheduler * fix: correct layout update condition in SpatialNavigationService to ensure proper component updates * docs: document Scheduler class changees * fix: initialize layoutUpdatedAt in SpatialNavigationService to ensure proper layout updates * fix: ensure currentTask is not triggered twice * fix: revert previous changes. Remove tick from priority tasks, add a try / finally block to the currentTask execution * Decouple event listeners and focus management (#214) * chore: update ESLint configuration to disable rules * feat: expand LayoutAdapter interface and refactor SpatialNavigationService to support custom event listeners * refactor: implement blurNode and update focusNode methods in LayoutAdapter for improved spatial navigation handling * feat: re-export adapters * docs: update SpatialNavigation and debugging guides to reflect new layout adapter usage * fix: await smartNavigate in keyDownEventListener to ensure proper behavior * fix: ensure data-focused attribute is set * feat: remove support for LayoutAdapter instance, use constructor option instead * React native layout adapter (#219) * feat: add NodeType interface and update FocusableComponent to support custom node types * feat: introduce ReactNativeLayoutAdapter * refactor: update ReactNativeLayoutAdapter to conditionally export based on platform * refactor: remove nativeMode from SpatialNavigationService and related options - Eliminated nativeMode property from SpatialNavigationServiceOptions and its usage throughout the service. - Updated related logic to ensure functionality remains intact without nativeMode. - Cleaned up code for improved readability and maintainability. * docs: enhance React Native TV support and update related documentation - Updated README.md to reflect full support for Android TV and Apple TV using the `@noriginmedia/norigin-spatial-navigation-react-native` package. - Revised SpatialNavigation.md to clarify the use of layout adapters and introduced new sections for React Native TV, including installation and initialization instructions. - Expanded useFocusable.md to specify the differences in ref handling between web and React Native TV. - Added a new guide for React Native TV detailing setup and usage. - Adjusted installation.md to include peer dependencies for React Native TV. * feat: add NodeTypeOverrides interface and enhance ReactNativeLayoutAdapter for improved customization * fix: add missing external dependencies in rollup configuration for React Native * fix: resolve undefined layout for Android TV with EMPTY_LAYOUT constant * chore: update TypeScript configuration for React Native to skip library checks * refactor: update EMPTY_LAYOUT to use undefined values and adjust export for platform-specific adapter * refactor: rename @noriginmedia/norigin-spatial-navigation-react-native-tvos package * Add extra compatibility for web bundlers like Vite or Webpack when using with React Native Web (#230) * feat: enhance rollup configuration and add web-specific entry point - Updated rollup configuration to support separate builds for web and common JS formats. - Added new entry point for web-specific functionality in src/index.web.ts. - Updated package.json exports to include web module paths. * Cleanup after rebase * Add nextFocusResolver to override default behavior (#231) * feat: add navigationStrategy to FocusableComponent and update SpatialNavigationService for custom navigation handling * refactor: rename navigationStrategy to nextFocusResolver * Create hot-falcons-begin.md * fix: add warning for invalid component in nextFocusResolver to prevent lost focus * Update packages/core/src/SpatialNavigation.ts Co-authored-by: Dmitriy Bryokhin <2877657+asgvard@users.noreply.github.com> --------- Co-authored-by: Dmitriy Bryokhin <2877657+asgvard@users.noreply.github.com> * fix: prevent priority tasks from being lost * fix: enqueue external setFocus calls * fix: rebase and async tests * chore: bump to major versions * docs: remove beta banner --------- Co-authored-by: Dmitriy Bryokhin <2877657+asgvard@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an optional
nextFocusResolverhook so a parent focus scope can override default spatial navigation when moving between siblings. When set on the parent focusable, arrow navigation among its children uses your function instead of cutoff coordinates and priority sorting.Motivation
Default spatial navigation is geometry-based (cutoff coordinates, RTL/LTR,
sortSiblingsByPriority). Some UIs need deterministic or domain-specific ordering (e.g. custom grids, masked lists, non-rect layouts, overlapped elements...). This change lets callers supply the next focus target explicitly while keeping the existing algorithm as the default when no strategy is provided.API
NextFocusResolver:FocusableComponent.navigationStrategy(optional) — stored and updated with addFocusable / updateFocusable.useFocusable({ navigationStrategy })— passes the strategy through registration and dependency updates.Behavior
During smartNavigate, the service reads nextFocusResolver from the parent (focusableComponents[parentFocusKey]).
If present: collects siblings with the same parentFocusKey that are focusable, calls nextFocusResolver(direction, focusKey, siblings), and uses its return value as the next component (skips default sibling filtering by layout cutoff, visual-debug sibling drawing for that path, and sortSiblingsByPriority).