Skip to content

Commit

Permalink
Focusable container agnostic methods available as top level exports +…
Browse files Browse the repository at this point in the history
… doesFocusableExist (#94)

Co-authored-by: Dmitriy Bryokhin <[email protected]>
  • Loading branch information
adrian-wozniak and asgvard authored Sep 11, 2023
1 parent 77b4f7d commit b78cdec
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 43 deletions.
51 changes: 27 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ It is useful when you first open the page, or i.e. when your modal Popup gets mo

```jsx
import React, { useEffect } from 'react';
import { useFocusable, FocusContext } from '@noriginmedia/norigin-spatial-navigation';
import { useFocusable, FocusContext, setFocus } from '@noriginmedia/norigin-spatial-navigation';

function Popup() {
const { ref, focusKey, focusSelf, setFocus } = useFocusable();
const { ref, focusKey, focusSelf } = useFocusable();

// Focusing self will focus the Popup, which will pass the focus down to the first Child (ButtonPrimary)
// Alternatively you can manually focus any other component by its 'focusKey'
Expand Down Expand Up @@ -297,6 +297,31 @@ setThrottle({
### `destroy`
Resets all the settings and the storage of focusable components. Disables the navigation service.

### `doesFocusableExist` (function) `(focusKey: string) => boolean`
Returns `true` if Focusable Container with given `focusKey` is created, `false` otherwise.

### `setFocus` (function) `(focusKey: string) => void`
Method to manually set the focus to a component providing its `focusKey`. If `focusKey` is not provided or
is equal to `ROOT_FOCUS_KEY`, an attempt of focusing one of the force-focusable components is made.
See `useFocusable` hook [`forceFocus`](#forcefocus-default-false) parameter for more details.

### `getCurrentFocusKey` (function) `() => string`
Returns the currently focused component's focus key.

### `navigateByDirection` (function) `(direction: string, focusDetails: FocusDetails) => void`
Method to manually navigation to a certain direction. I.e. you can assign a mouse-wheel to navigate Up and Down.
Also useful when you have some "Arrow-like" UI in the app that is meant to navigate in certain direction when pressed
with the mouse or a "magic remote" on some TVs.

### `pause` (function)
Pauses all the key event handlers.

### `resume` (function)
Resumes all the key event handlers.

### `updateAllLayouts` (function)
Manually recalculate all the layouts. Rarely used.

### `useFocusable` hook
This hook is the main link between the React component (its DOM element) and the navigation service.
It is used to register the component in the service, get its `focusKey`, `focused` state etc.
Expand Down Expand Up @@ -398,11 +423,6 @@ function Button() {
Method to set the focus on the current component. I.e. to set the focus to the Page (Container) when it is mounted, or
the Popup component when it is displayed.

##### `setFocus` (function) `(focusKey: string) => void`
Method to manually set the focus to a component providing its `focusKey`. If `focusKey` is not provided or
is equal to `ROOT_FOCUS_KEY`, an attempt of focusing one of the force-focusable components is made.
See `useFocusable` hook [`forceFocus`](#forcefocus-default-false) parameter for more details.

##### `focused` (boolean)
Flag that indicates that the current component is focused.

Expand All @@ -414,23 +434,6 @@ Only works when `trackChildren` is enabled!
String that contains the focus key for the component. It is either the same as `focusKey` passed to the hook params,
or an automatically generated one.

#### `getCurrentFocusKey` (function) `() => string`
Returns the currently focused component's focus key.

##### `navigateByDirection` (function) `(direction: string, focusDetails: FocusDetails) => void`
Method to manually navigation to a certain direction. I.e. you can assign a mouse-wheel to navigate Up and Down.
Also useful when you have some "Arrow-like" UI in the app that is meant to navigate in certain direction when pressed
with the mouse or a "magic remote" on some TVs.

##### `pause` (function)
Pauses all the key event handlers.

##### `resume` (function)
Resumes all the key event handlers.

##### `updateAllLayouts` (function)
Manually recalculate all the layouts. Rarely used.

### `FocusContext` (required for Focusable Containers)
Used to provide the `focusKey` of the current Focusable Container down the Tree to the next child level. [See Example](#wrapping-leaf-components-with-a-focusable-container)

Expand Down
25 changes: 21 additions & 4 deletions src/SpatialNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ class SpatialNavigationService {
this.destroy = this.destroy.bind(this);
this.setKeyMap = this.setKeyMap.bind(this);
this.getCurrentFocusKey = this.getCurrentFocusKey.bind(this);
this.doesFocusableExist = this.doesFocusableExist.bind(this);

this.setFocusDebounced = debounce(this.setFocus, AUTO_RESTORE_FOCUS_DELAY, {
leading: false,
Expand Down Expand Up @@ -826,7 +827,7 @@ class SpatialNavigationService {
* navigateByDirection('right') // The focus is moved to right
*/
navigateByDirection(direction: string, focusDetails: FocusDetails) {
if (this.paused === true || this.nativeMode) {
if (this.paused === true || !this.enabled || this.nativeMode) {
return;
}

Expand Down Expand Up @@ -1483,7 +1484,7 @@ class SpatialNavigationService {
// Cancel any pending auto-restore focus calls if we are setting focus manually
this.setFocusDebounced.cancel();

if (!this.enabled) {
if (!this.enabled || this.nativeMode) {
return;
}

Expand All @@ -1509,7 +1510,7 @@ class SpatialNavigationService {
}

updateAllLayouts() {
if (this.nativeMode) {
if (!this.enabled || this.nativeMode) {
return;
}

Expand Down Expand Up @@ -1578,6 +1579,10 @@ class SpatialNavigationService {
isNativeMode() {
return this.nativeMode;
}

doesFocusableExist(focusKey: string) {
return !!this.focusableComponents[focusKey];
}
}

/**
Expand All @@ -1586,4 +1591,16 @@ class SpatialNavigationService {
/** @internal */
export const SpatialNavigation = new SpatialNavigationService();

export const { init, setThrottle, destroy, setKeyMap } = SpatialNavigation;
export const {
init,
setThrottle,
destroy,
setKeyMap,
setFocus,
navigateByDirection,
pause,
resume,
updateAllLayouts,
getCurrentFocusKey,
doesFocusableExist
} = SpatialNavigation;
16 changes: 1 addition & 15 deletions src/useFocusable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@ export interface UseFocusableResult {
focused: boolean;
hasFocusedChild: boolean;
focusKey: string;
setFocus: (focusKey: string, focusDetails?: FocusDetails) => void;
navigateByDirection: (direction: string, focusDetails: FocusDetails) => void;
pause: () => void;
resume: () => void;
updateAllLayouts: () => void;
getCurrentFocusKey: () => string;
}

const useFocusableHook = <P>({
Expand Down Expand Up @@ -208,15 +202,7 @@ const useFocusableHook = <P>({
focusSelf,
focused,
hasFocusedChild,
focusKey, // returns either the same focusKey as passed in, or generated one
setFocus: SpatialNavigation.isNativeMode()
? noop
: SpatialNavigation.setFocus,
navigateByDirection: SpatialNavigation.navigateByDirection,
pause: SpatialNavigation.pause,
resume: SpatialNavigation.resume,
updateAllLayouts: SpatialNavigation.updateAllLayouts,
getCurrentFocusKey: SpatialNavigation.getCurrentFocusKey
focusKey // returns either the same focusKey as passed in, or generated one
};
};

Expand Down

0 comments on commit b78cdec

Please sign in to comment.