Skip to content
This repository has been archived by the owner on May 5, 2023. It is now read-only.

Commit

Permalink
Added blockNavigationOut prop (#72)
Browse files Browse the repository at this point in the history
* Added blockNavigationOut prop

* Updated changelog

* Added blockNavigationOut as a config prop

* Updated readme
  • Loading branch information
guilleccc authored Aug 25, 2020
1 parent 62a0310 commit c625b54
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.12.5]
### Added
- Added `blockNavigationOut` to avoid focus out from the selected component.

## [2.12.4]
### Fixed
- Fixed issue where this library didn't work in SSR environments due to references to DOM-only variables
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ To determine whether parent component should focus the first available child com
* **true (default)**
* **false**

##### `blockNavigationOut`: boolean
Disable the navigation out from the selected component. It can be useful when a user opens a popup (or screen) and you don't want to allow the user to focus other components outside this area.

It doesn't block focus set programmatically by `setFocus`.
* **false (default)**
* **true**

## Props that can be applied to HOC
All these props are optional.

Expand All @@ -259,6 +266,9 @@ Same as in [config](#config).
### `autoRestoreFocus`: boolean
Same as in [config](#config).

### `blockNavigationOut`: boolean
Same as in [config](#config).

### `focusable`: boolean
Determine whether this component should be focusable (in other words, whether it's *currently* participating in the spatial navigation tree). This allows a focusable component to be ignored as a navigation target despite being mounted (e.g. due to being off-screen, hidden, or temporarily disabled).

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@noriginmedia/react-spatial-navigation",
"version": "2.12.4",
"version": "2.12.5",
"description": "HOC-based Spatial Navigation (key navigation) solution for React",
"main": "dist/index.js",
"files": [
Expand Down
25 changes: 24 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const programs = shuffle([{
}]);

const RETURN_KEY = 8;
const B_KEY = 66;

/* eslint-disable react/prefer-stateless-function */
class MenuItem extends React.PureComponent {
Expand Down Expand Up @@ -190,12 +191,31 @@ class Content extends React.PureComponent {
super(props);

this.state = {
currentProgram: null
currentProgram: null,
blockNavigationOut: false
};

this.onPressKey = this.onPressKey.bind(this);
this.onProgramPress = this.onProgramPress.bind(this);
}

componentDidMount() {
window.addEventListener('keydown', this.onPressKey);
}

componentWillUnmount() {
window.removeEventListener('keydown', this.onPressKey);
}

onPressKey(event) {
if (event.keyCode === B_KEY) {
const {blockNavigationOut: blocked} = this.state;

console.warn(`blockNavigationOut: ${!blocked}. Press B to ${blocked ? 'block' : 'unblock '}`);
this.setState((prevState) => ({blockNavigationOut: !prevState.blockNavigationOut}));
}
}

onProgramPress(programProps, {pressedKeys} = {}) {
if (pressedKeys && pressedKeys[KEY_ENTER] > 1) {
return;
Expand All @@ -206,13 +226,16 @@ class Content extends React.PureComponent {
}

render() {
const {blockNavigationOut} = this.state;

// console.log('content rendered: ', this.props.realFocusKey);

return (<View style={styles.content}>
<Active program={this.state.currentProgram} />
<CategoriesFocusable
focusKey={'CATEGORIES'}
onProgramPress={this.onProgramPress}
blockNavigationOut={blockNavigationOut}
/>
</View>);
}
Expand Down
11 changes: 8 additions & 3 deletions src/spatialNavigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,9 @@ class SpatialNavigation {

this.saveLastFocusedChildKey(parentComponent, focusKey);

this.smartNavigate(direction, parentFocusKey, details);
if (!parentComponent || !parentComponent.blockNavigationOut) {
this.smartNavigate(direction, parentFocusKey, details);
}
}
}
}
Expand Down Expand Up @@ -728,7 +730,8 @@ class SpatialNavigation {
onUpdateHasFocusedChild,
preferredChildFocusKey,
autoRestoreFocus,
focusable
focusable,
blockNavigationOut
}) {
this.focusableComponents[focusKey] = {
focusKey,
Expand All @@ -745,6 +748,7 @@ class SpatialNavigation {
lastFocusedChildKey: null,
preferredChildFocusKey,
focusable,
blockNavigationOut,
autoRestoreFocus,
layout: {
x: 0,
Expand Down Expand Up @@ -990,7 +994,7 @@ class SpatialNavigation {
});
}

updateFocusable(focusKey, {node, preferredChildFocusKey, focusable}) {
updateFocusable(focusKey, {node, preferredChildFocusKey, focusable, blockNavigationOut}) {
if (this.nativeMode) {
return;
}
Expand All @@ -1000,6 +1004,7 @@ class SpatialNavigation {
if (component) {
component.preferredChildFocusKey = preferredChildFocusKey;
component.focusable = focusable;
component.blockNavigationOut = blockNavigationOut;

if (node) {
component.node = node;
Expand Down
13 changes: 9 additions & 4 deletions src/withFocusable.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const omitProps = (keys) => mapProps((props) => omit(props, keys));
const withFocusable = ({
forgetLastFocusedChild: configForgetLastFocusedChild = false,
trackChildren: configTrackChildren = false,
autoRestoreFocus: configAutoRestoreFocus
autoRestoreFocus: configAutoRestoreFocus,
blockNavigationOut: configBlockNavigationOut = false
} = {}) => compose(
getContext({
/**
Expand Down Expand Up @@ -111,7 +112,8 @@ const withFocusable = ({
onUpdateHasFocusedChild,
trackChildren,
focusable = true,
autoRestoreFocus = true
autoRestoreFocus = true,
blockNavigationOut = false
} = this.props;

const node = SpatialNavigation.isNativeMode() ? this : findDOMNode(this);
Expand All @@ -129,6 +131,7 @@ const withFocusable = ({
onUpdateHasFocusedChild,
forgetLastFocusedChild: (configForgetLastFocusedChild || forgetLastFocusedChild),
trackChildren: (configTrackChildren || trackChildren),
blockNavigationOut: (configBlockNavigationOut || blockNavigationOut),
autoRestoreFocus: configAutoRestoreFocus !== undefined ? configAutoRestoreFocus : autoRestoreFocus,
focusable
});
Expand All @@ -137,15 +140,17 @@ const withFocusable = ({
const {
realFocusKey: focusKey,
preferredChildFocusKey,
focusable = true
focusable = true,
blockNavigationOut = false
} = this.props;

const node = SpatialNavigation.isNativeMode() ? this : findDOMNode(this);

SpatialNavigation.updateFocusable(focusKey, {
node,
preferredChildFocusKey,
focusable
focusable,
blockNavigationOut: (configBlockNavigationOut || blockNavigationOut)
});
},
componentWillUnmount() {
Expand Down

0 comments on commit c625b54

Please sign in to comment.