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

Commit

Permalink
Added a smart navigation method by direction, refactoring (#36)
Browse files Browse the repository at this point in the history
* Added a smart navigation method by direction, refactoring

* PR edits

* Returned the default codestyle
  • Loading branch information
yarikleto authored and asgvard committed Sep 17, 2019
1 parent 61197cb commit 69c9991
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ 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.9.0]
### Added
- Added smart focusing by direction (left, right, top, down), if you can't use buttons or focusing by key. Use `navigateByDirection` method for it.


## [2.8.4]
### Fixed
- Fixed useless `logIndex` update.
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,16 @@ In Native mode this method is ignored (`noop`).
setFocus(); // set focus to self
setFocus('SOME_COMPONENT'); // set focus to another component if you know its focus key
```
### `navigateByDirection`: function
Move the focus by direction, if you can't use buttons or focusing by key.

```jsx
navigateByDirection('left'); // The focus is moved to left
navigateByDirection('right'); // The focus is moved to right
navigateByDirection('up'); // The focus is moved to up
navigateByDirection('down'); // The focus is moved to down
```


### `stealFocus`: function
This method works exactly like `setFocus`, but it always sets focus to current component no matter which params you pass in.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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.8.4",
"version": "2.9.0",
"description": "HOC-based Spatial Navigation (key navigation) solution for React",
"main": "dist/index.js",
"files": [
Expand Down
45 changes: 44 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import shuffle from 'lodash/shuffle';
import throttle from 'lodash/throttle';
import {View, Text, StyleSheet, TouchableOpacity, ScrollView} from 'react-native';
import withFocusable from './withFocusable';
import SpatialNavigation from './spatialNavigation';
Expand Down Expand Up @@ -393,6 +394,42 @@ Categories.propTypes = {
const CategoriesFocusable = withFocusable()(Categories);

class Spatial extends React.PureComponent {
constructor(props) {
super(props);

this.onWheel = this.onWheel.bind(this);
this.throttledWheelHandler = throttle(this.throttledWheelHandler.bind(this), 500, {trailing: false});
}

componentDidMount() {
window.addEventListener('wheel', this.onWheel, {passive: false});
}

componentWillUnmount() {
window.removeEventListener('wheel', this.onWheel);
}

onWheel(event) {
event.preventDefault();
this.throttledWheelHandler(event);
}

throttledWheelHandler(event) {
event.preventDefault();
const {deltaY, deltaX} = event;
const {navigateByDirection} = this.props;

if (deltaY > 1) {
navigateByDirection('down');
} else if (deltaY < 0) {
navigateByDirection('up');
} else if (deltaX > 1) {
navigateByDirection('right');
} else if (deltaX < 1) {
navigateByDirection('left');
}
}

render() {
return (<View style={styles.wrapper}>
<MenuFocusable
Expand All @@ -405,8 +442,14 @@ class Spatial extends React.PureComponent {
}
}

Spatial.propTypes = {
navigateByDirection: PropTypes.func.isRequired
};

const SpatialFocusable = withFocusable()(Spatial);

const App = () => (<View>
<Spatial />
<SpatialFocusable focusable={false} />
</View>);

export default App;
49 changes: 36 additions & 13 deletions src/spatialNavigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ class SpatialNavigation {
this.pause = this.pause.bind(this);
this.resume = this.resume.bind(this);
this.setFocus = this.setFocus.bind(this);
this.navigateByDirection = this.navigateByDirection.bind(this);
this.init = this.init.bind(this);
this.setKeyMap = this.setKeyMap.bind(this);

Expand Down Expand Up @@ -384,23 +385,22 @@ class SpatialNavigation {
return;
}

if (eventType === KEY_ENTER && this.focusKey) {
event.preventDefault();
event.stopPropagation();
event.preventDefault();
event.stopPropagation();

if (eventType === KEY_ENTER && this.focusKey) {
this.onEnterPress();
} else {
event.preventDefault();
event.stopPropagation();

const preventDefaultNavigation = this.onArrowPress(eventType) === false;
return;
}

const preventDefaultNavigation = this.onArrowPress(eventType) === false;

if (preventDefaultNavigation) {
this.log('keyDownEventListener', 'default navigation prevented');
this.visualDebugger && this.visualDebugger.clear();
} else {
this.onKeyEvent(event.keyCode);
}
if (preventDefaultNavigation) {
this.log('keyDownEventListener', 'default navigation prevented');
this.visualDebugger && this.visualDebugger.clear();
} else {
this.onKeyEvent(event.keyCode);
}
};

Expand Down Expand Up @@ -467,6 +467,29 @@ class SpatialNavigation {
return component && component.onArrowPressHandler && component.onArrowPressHandler(...args);
}

/**
* Move focus by direction, if you can't use buttons or focusing by key.
*
* @param {string} direction
*
* @example
* navigateByDirection('right') // The focus is moved to right
*/
navigateByDirection(direction) {
if (this.paused === true) {
return;
}

const validDirections = [DIRECTION_DOWN, DIRECTION_UP, DIRECTION_LEFT, DIRECTION_RIGHT];

if (validDirections.includes(direction)) {
this.log('navigateByDirection', 'direction', direction);
this.smartNavigate(direction);
} else {
this.log('navigateByDirection', `Invalid direction. You passed: \`${direction}\`, but you can use only these: `, validDirections);
}
}

onKeyEvent(keyCode) {
this.visualDebugger && this.visualDebugger.clear();

Expand Down
2 changes: 2 additions & 0 deletions src/withFocusable.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const withFocusable = ({
*/
setFocus: SpatialNavigation.isNativeMode() ? noop : SpatialNavigation.setFocus.bind(null, realFocusKey),

navigateByDirection: SpatialNavigation.navigateByDirection,

/**
* In Native mode this is the only way to mark component as focused.
* This method always steals focus onto current component no matter which arguments are passed in.
Expand Down

0 comments on commit 69c9991

Please sign in to comment.