Skip to content

Add nextFocusResolver to override default behavior#231

Merged
xavi160 merged 5 commits into
nextfrom
navigation-strategy
Apr 28, 2026
Merged

Add nextFocusResolver to override default behavior#231
xavi160 merged 5 commits into
nextfrom
navigation-strategy

Conversation

@xavi160

@xavi160 xavi160 commented Apr 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an optional nextFocusResolver hook 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

  • Type NextFocusResolver:
    (
      direction: Direction,
      focusKey: string,
      siblings: FocusableComponent[]
    ) => FocusableComponent | null

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).

@xavi160 xavi160 self-assigned this Apr 27, 2026
@changeset-bot

changeset-bot Bot commented Apr 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c6423e5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@noriginmedia/norigin-spatial-navigation-core Patch
@noriginmedia/norigin-spatial-navigation-react Patch

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

@xavi160
xavi160 changed the base branch from main to next April 27, 2026 10:52
Comment thread packages/core/src/SpatialNavigation.ts Outdated
Comment thread packages/core/src/SpatialNavigation.ts Outdated
@xavi160
xavi160 requested a review from asgvard April 28, 2026 07:20
@xavi160
xavi160 marked this pull request as ready for review April 28, 2026 07:20
@xavi160
xavi160 requested a review from a team as a code owner April 28, 2026 07:20
@xavi160 xavi160 changed the title Add navigationStrategy to override default behavior Add nextFocusResolver to override default behavior Apr 28, 2026
Comment thread packages/core/src/SpatialNavigation.ts Outdated
Co-authored-by: Dmitriy Bryokhin <2877657+asgvard@users.noreply.github.com>
@xavi160
xavi160 requested a review from asgvard April 28, 2026 08:44
@xavi160
xavi160 merged commit 8fb1ac6 into next Apr 28, 2026
1 check passed
@xavi160
xavi160 deleted the navigation-strategy branch April 28, 2026 09:24
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>
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.

3 participants