@noriginmedia/react-spatial-navigation
Advanced tools
Comparing version 2.6.0 to 2.7.1
@@ -7,3 +7,7 @@ # Changelog | ||
## [Unreleased] | ||
## [2.7.0] | ||
### Added | ||
- `focusable` prop that enables component as a focusable target. Default is true. Usable when you need to temporarily disable focusable behaviour on the component. E.g. disabled button state. | ||
### Changed | ||
- Moved `react` and `react-dom` to peer dependencies | ||
@@ -10,0 +14,0 @@ ## [2.6.0] |
@@ -199,4 +199,8 @@ 'use strict'; | ||
value: function componentDidMount() { | ||
this.props.setFocus(); | ||
var _this3 = this; | ||
setTimeout(function () { | ||
_this3.props.setFocus(); | ||
}, 0); | ||
window.addEventListener('keydown', this.onPressKey); | ||
@@ -254,10 +258,10 @@ } | ||
var _this3 = _possibleConstructorReturn(this, (Content.__proto__ || Object.getPrototypeOf(Content)).call(this, props)); | ||
var _this4 = _possibleConstructorReturn(this, (Content.__proto__ || Object.getPrototypeOf(Content)).call(this, props)); | ||
_this3.state = { | ||
_this4.state = { | ||
currentProgram: null | ||
}; | ||
_this3.onProgramPress = _this3.onProgramPress.bind(_this3); | ||
return _this3; | ||
_this4.onProgramPress = _this4.onProgramPress.bind(_this4); | ||
return _this4; | ||
} | ||
@@ -404,9 +408,9 @@ | ||
var _this6 = _possibleConstructorReturn(this, (Category.__proto__ || Object.getPrototypeOf(Category)).call(this, props)); | ||
var _this7 = _possibleConstructorReturn(this, (Category.__proto__ || Object.getPrototypeOf(Category)).call(this, props)); | ||
_this6.scrollRef = null; | ||
_this7.scrollRef = null; | ||
_this6.onProgramFocused = _this6.onProgramFocused.bind(_this6); | ||
_this6.onProgramArrowPress = _this6.onProgramArrowPress.bind(_this6); | ||
return _this6; | ||
_this7.onProgramFocused = _this7.onProgramFocused.bind(_this7); | ||
_this7.onProgramArrowPress = _this7.onProgramArrowPress.bind(_this7); | ||
return _this7; | ||
} | ||
@@ -440,3 +444,3 @@ | ||
value: function render() { | ||
var _this7 = this; | ||
var _this8 = this; | ||
@@ -459,3 +463,3 @@ // console.log('Category rendered: ', this.props.realFocusKey); | ||
if (reference) { | ||
_this7.scrollRef = reference; | ||
_this8.scrollRef = reference; | ||
} | ||
@@ -466,10 +470,10 @@ } | ||
return _react2.default.createElement(ProgramFocusable, _extends({}, program, { | ||
focusKey: 'PROGRAM-' + _this7.props.realFocusKey + '-' + index, | ||
onPress: _this7.props.onProgramPress, | ||
onEnterPress: _this7.props.onProgramPress, | ||
focusKey: 'PROGRAM-' + _this8.props.realFocusKey + '-' + index, | ||
onPress: _this8.props.onProgramPress, | ||
onEnterPress: _this8.props.onProgramPress, | ||
key: program.title, | ||
onBecameFocused: _this7.onProgramFocused, | ||
onArrowPress: _this7.onProgramArrowPress, | ||
onBecameFocused: _this8.onProgramFocused, | ||
onArrowPress: _this8.onProgramArrowPress, | ||
programIndex: index, | ||
categoryIndex: _this7.props.categoryIndex | ||
categoryIndex: _this8.props.categoryIndex | ||
})); | ||
@@ -501,8 +505,8 @@ }) | ||
var _this8 = _possibleConstructorReturn(this, (Categories.__proto__ || Object.getPrototypeOf(Categories)).call(this, props)); | ||
var _this9 = _possibleConstructorReturn(this, (Categories.__proto__ || Object.getPrototypeOf(Categories)).call(this, props)); | ||
_this8.scrollRef = null; | ||
_this9.scrollRef = null; | ||
_this8.onCategoryFocused = _this8.onCategoryFocused.bind(_this8); | ||
return _this8; | ||
_this9.onCategoryFocused = _this9.onCategoryFocused.bind(_this9); | ||
return _this9; | ||
} | ||
@@ -522,3 +526,3 @@ | ||
value: function render() { | ||
var _this9 = this; | ||
var _this10 = this; | ||
@@ -532,3 +536,3 @@ // console.log('Categories rendered: ', this.props.realFocusKey); | ||
if (reference) { | ||
_this9.scrollRef = reference; | ||
_this10.scrollRef = reference; | ||
} | ||
@@ -542,5 +546,5 @@ }, | ||
}, category, { | ||
onProgramPress: _this9.props.onProgramPress, | ||
onProgramPress: _this10.props.onProgramPress, | ||
key: category.title, | ||
onBecameFocused: _this9.onCategoryFocused, | ||
onBecameFocused: _this10.onCategoryFocused, | ||
categoryIndex: index | ||
@@ -547,0 +551,0 @@ |
@@ -506,2 +506,9 @@ 'use strict'; | ||
/* Suppress onEnterPress if the focused item happens to lose its 'focused' status. */ | ||
if (!component.focusable) { | ||
this.log('onEnterPress', 'componentNotFocusable'); | ||
return; | ||
} | ||
component.onEnterPressHandler && component.onEnterPressHandler(); | ||
@@ -544,2 +551,3 @@ } | ||
/* We will not check whether currentComponent is focusable; it's fine to navigate AWAY from a disabled component. */ | ||
if (currentComponent) { | ||
@@ -560,3 +568,3 @@ var parentFocusKey = currentComponent.parentFocusKey, | ||
var siblings = (0, _filter2.default)(this.focusableComponents, function (component) { | ||
if (component.parentFocusKey === parentFocusKey) { | ||
if (component.parentFocusKey === parentFocusKey && component.focusable) { | ||
var siblingCutoffCoordinate = SpatialNavigation.getCutoffCoordinate(isVerticalDirection, isIncrementalDirection, true, component.layout); | ||
@@ -606,2 +614,3 @@ | ||
value: function saveLastFocusedChildKey(component, focusKey) { | ||
/* We won't check whether component is focusable; it's fine to save a disabled component as the lastFocusedChild. */ | ||
if (component) { | ||
@@ -645,3 +654,3 @@ this.log('saveLastFocusedChildKey', component.focusKey + ' lastFocusedChildKey set', focusKey); | ||
var children = (0, _filter2.default)(this.focusableComponents, function (component) { | ||
return component.parentFocusKey === targetFocusKey; | ||
return component.parentFocusKey === targetFocusKey && component.focusable; | ||
}); | ||
@@ -662,3 +671,3 @@ | ||
*/ | ||
if (lastFocusedChildKey && !targetComponent.forgetLastFocusedChild && this.isFocusableComponent(lastFocusedChildKey)) { | ||
if (lastFocusedChildKey && !targetComponent.forgetLastFocusedChild && this.isParticipatingFocusableComponent(lastFocusedChildKey)) { | ||
this.log('getNextFocusKey', 'lastFocusedChildKey will be focused', lastFocusedChildKey); | ||
@@ -672,3 +681,3 @@ | ||
*/ | ||
if (preferredChildFocusKey && this.isFocusableComponent(preferredChildFocusKey)) { | ||
if (preferredChildFocusKey && this.isParticipatingFocusableComponent(preferredChildFocusKey)) { | ||
this.log('getNextFocusKey', 'preferredChildFocusKey will be focused', preferredChildFocusKey); | ||
@@ -717,3 +726,4 @@ | ||
onUpdateHasFocusedChild = _ref2.onUpdateHasFocusedChild, | ||
preferredChildFocusKey = _ref2.preferredChildFocusKey; | ||
preferredChildFocusKey = _ref2.preferredChildFocusKey, | ||
focusable = _ref2.focusable; | ||
@@ -733,2 +743,3 @@ this.focusableComponents[focusKey] = { | ||
preferredChildFocusKey: preferredChildFocusKey, | ||
focusable: focusable, | ||
layout: { | ||
@@ -804,3 +815,3 @@ x: 0, | ||
value: function setCurrentFocusedKey(focusKey) { | ||
if (this.isFocusableComponent(this.focusKey) && focusKey !== this.focusKey) { | ||
if (this.isParticipatingFocusableComponent(this.focusKey) && focusKey !== this.focusKey) { | ||
var oldComponent = this.focusableComponents[this.focusKey]; | ||
@@ -903,6 +914,17 @@ var parentComponent = this.focusableComponents[oldComponent.parentFocusKey]; | ||
} | ||
/** | ||
* Checks whether the focusableComponent is actually participating in spatial navigation (in other words, is a | ||
* 'focusable' focusableComponent). Seems less confusing than calling it isFocusableFocusableComponent() | ||
*/ | ||
}, { | ||
key: 'isParticipatingFocusableComponent', | ||
value: function isParticipatingFocusableComponent(focusKey) { | ||
return this.isFocusableComponent(focusKey) && this.focusableComponents[focusKey].focusable; | ||
} | ||
}, { | ||
key: 'onIntermediateNodeBecameFocused', | ||
value: function onIntermediateNodeBecameFocused(focusKey) { | ||
this.isFocusableComponent(focusKey) && this.focusableComponents[focusKey].onBecameFocusedHandler(this.getNodeLayoutByFocusKey(focusKey)); | ||
this.isParticipatingFocusableComponent(focusKey) && this.focusableComponents[focusKey].onBecameFocusedHandler(this.getNodeLayoutByFocusKey(focusKey)); | ||
} | ||
@@ -933,2 +955,8 @@ }, { | ||
if (!this.isParticipatingFocusableComponent(newFocusKey)) { | ||
this.log('setFocus', 'noParticipatingFocusTargets', newFocusKey); | ||
return; | ||
} | ||
this.log('setFocus', 'newFocusKey', newFocusKey); | ||
@@ -984,3 +1012,4 @@ | ||
var node = _ref4.node, | ||
preferredChildFocusKey = _ref4.preferredChildFocusKey; | ||
preferredChildFocusKey = _ref4.preferredChildFocusKey, | ||
focusable = _ref4.focusable; | ||
@@ -995,2 +1024,3 @@ if (this.nativeMode) { | ||
component.preferredChildFocusKey = preferredChildFocusKey; | ||
component.focusable = focusable; | ||
@@ -997,0 +1027,0 @@ if (node) { |
@@ -188,3 +188,5 @@ 'use strict'; | ||
onUpdateHasFocusedChild = _props.onUpdateHasFocusedChild, | ||
trackChildren = _props.trackChildren; | ||
trackChildren = _props.trackChildren, | ||
_props$focusable = _props.focusable, | ||
focusable = _props$focusable === undefined ? true : _props$focusable; | ||
@@ -205,3 +207,4 @@ | ||
forgetLastFocusedChild: configForgetLastFocusedChild || forgetLastFocusedChild, | ||
trackChildren: configTrackChildren || trackChildren | ||
trackChildren: configTrackChildren || trackChildren, | ||
focusable: focusable | ||
}); | ||
@@ -214,3 +217,5 @@ }, | ||
onBecameFocusedHandler = _props2.onBecameFocusedHandler, | ||
preferredChildFocusKey = _props2.preferredChildFocusKey; | ||
preferredChildFocusKey = _props2.preferredChildFocusKey, | ||
_props2$focusable = _props2.focusable, | ||
focusable = _props2$focusable === undefined ? true : _props2$focusable; | ||
@@ -222,3 +227,4 @@ | ||
node: node, | ||
preferredChildFocusKey: preferredChildFocusKey | ||
preferredChildFocusKey: preferredChildFocusKey, | ||
focusable: focusable | ||
}); | ||
@@ -225,0 +231,0 @@ |
{ | ||
"name": "@noriginmedia/react-spatial-navigation", | ||
"version": "2.6.0", | ||
"version": "2.7.1", | ||
"description": "HOC-based Spatial Navigation (key navigation) solution for React", | ||
@@ -23,2 +23,7 @@ "main": "dist/index.js", | ||
"author": "Dmitriy Bryokhin <dmitriy.bryokhin@noriginmedia.com>", | ||
"contributors": [ | ||
"Dmitriy Bryokhin <dmitriy.bryokhin@noriginmedia.com>", | ||
"Jamie Birch <jamie.birch@s-and-t.com>", | ||
"Antonio Salvati <antonio.salvati@noriginmedia.com>" | ||
], | ||
"license": "MIT", | ||
@@ -29,7 +34,10 @@ "bugs": { | ||
"homepage": "https://github.com/NoriginMedia/react-spatial-navigation#readme", | ||
"peerDependencies": { | ||
"react": ">=16.5.1", | ||
"react-dom": ">=16.5.1", | ||
"react-native-web": "^0.11.2" | ||
}, | ||
"dependencies": { | ||
"lodash": "^4.17.0", | ||
"lodash": "^4.17.13", | ||
"prop-types": "^15.6.2", | ||
"react": "^16.5.2", | ||
"react-dom": "^16.5.2", | ||
"recompose": "^0.30.0" | ||
@@ -48,2 +56,4 @@ }, | ||
"pre-commit": "^1.2.2", | ||
"react": "^16.5.2", | ||
"react-dom": "^16.5.2", | ||
"react-native-web": "^0.11.2" | ||
@@ -50,0 +60,0 @@ }, |
@@ -247,2 +247,10 @@ # react-spatial-navigation | ||
### `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). | ||
Note that behaviour is undefined for trees of components in which an `focusable={false}` component has any `focusable={true}` components as descendants; it is recommended to ensure that all components in a given branch of the spatial navigation tree have a common `focusable` state. | ||
* **false** | ||
* **true (default)** | ||
### `focusKey`: string | ||
@@ -249,0 +257,0 @@ String that is used as a component focus key. Should be **unique**, otherwise it will override previously stored component with the same focus key in the Spatial Navigation service storage of focusable components. If this is not specified, the focus key will be generated automatically. |
@@ -145,3 +145,5 @@ /* eslint-disable react/no-multi-comp */ | ||
componentDidMount() { | ||
this.props.setFocus(); | ||
setTimeout(() => { | ||
this.props.setFocus(); | ||
}, 0); | ||
@@ -148,0 +150,0 @@ window.addEventListener('keydown', this.onPressKey); |
@@ -435,2 +435,9 @@ import filter from 'lodash/filter'; | ||
/* Suppress onEnterPress if the focused item happens to lose its 'focused' status. */ | ||
if (!component.focusable) { | ||
this.log('onEnterPress', 'componentNotFocusable'); | ||
return; | ||
} | ||
component.onEnterPressHandler && component.onEnterPressHandler(); | ||
@@ -470,2 +477,3 @@ } | ||
/* We will not check whether currentComponent is focusable; it's fine to navigate AWAY from a disabled component. */ | ||
if (currentComponent) { | ||
@@ -488,3 +496,3 @@ const {parentFocusKey, focusKey, layout} = currentComponent; | ||
const siblings = filter(this.focusableComponents, (component) => { | ||
if (component.parentFocusKey === parentFocusKey) { | ||
if (component.parentFocusKey === parentFocusKey && component.focusable) { | ||
const siblingCutoffCoordinate = SpatialNavigation.getCutoffCoordinate( | ||
@@ -549,2 +557,3 @@ isVerticalDirection, | ||
saveLastFocusedChildKey(component, focusKey) { | ||
/* We won't check whether component is focusable; it's fine to save a disabled component as the lastFocusedChild. */ | ||
if (component) { | ||
@@ -582,3 +591,6 @@ this.log('saveLastFocusedChildKey', `${component.focusKey} lastFocusedChildKey set`, focusKey); | ||
const children = filter(this.focusableComponents, (component) => component.parentFocusKey === targetFocusKey); | ||
const children = filter( | ||
this.focusableComponents, | ||
(component) => component.parentFocusKey === targetFocusKey && component.focusable | ||
); | ||
@@ -598,3 +610,3 @@ if (children.length > 0) { | ||
!targetComponent.forgetLastFocusedChild && | ||
this.isFocusableComponent(lastFocusedChildKey) | ||
this.isParticipatingFocusableComponent(lastFocusedChildKey) | ||
) { | ||
@@ -609,3 +621,3 @@ this.log('getNextFocusKey', 'lastFocusedChildKey will be focused', lastFocusedChildKey); | ||
*/ | ||
if (preferredChildFocusKey && this.isFocusableComponent(preferredChildFocusKey)) { | ||
if (preferredChildFocusKey && this.isParticipatingFocusableComponent(preferredChildFocusKey)) { | ||
this.log('getNextFocusKey', 'preferredChildFocusKey will be focused', preferredChildFocusKey); | ||
@@ -647,3 +659,4 @@ | ||
onUpdateHasFocusedChild, | ||
preferredChildFocusKey | ||
preferredChildFocusKey, | ||
focusable | ||
}) { | ||
@@ -663,2 +676,3 @@ this.focusableComponents[focusKey] = { | ||
preferredChildFocusKey, | ||
focusable, | ||
layout: { | ||
@@ -729,3 +743,3 @@ x: 0, | ||
setCurrentFocusedKey(focusKey) { | ||
if (this.isFocusableComponent(this.focusKey) && focusKey !== this.focusKey) { | ||
if (this.isParticipatingFocusableComponent(this.focusKey) && focusKey !== this.focusKey) { | ||
const oldComponent = this.focusableComponents[this.focusKey]; | ||
@@ -820,4 +834,12 @@ const parentComponent = this.focusableComponents[oldComponent.parentFocusKey]; | ||
/** | ||
* Checks whether the focusableComponent is actually participating in spatial navigation (in other words, is a | ||
* 'focusable' focusableComponent). Seems less confusing than calling it isFocusableFocusableComponent() | ||
*/ | ||
isParticipatingFocusableComponent(focusKey) { | ||
return this.isFocusableComponent(focusKey) && this.focusableComponents[focusKey].focusable; | ||
} | ||
onIntermediateNodeBecameFocused(focusKey) { | ||
this.isFocusableComponent(focusKey) && | ||
this.isParticipatingFocusableComponent(focusKey) && | ||
this.focusableComponents[focusKey].onBecameFocusedHandler(this.getNodeLayoutByFocusKey(focusKey)); | ||
@@ -846,2 +868,8 @@ } | ||
if (!this.isParticipatingFocusableComponent(newFocusKey)) { | ||
this.log('setFocus', 'noParticipatingFocusTargets', newFocusKey); | ||
return; | ||
} | ||
this.log('setFocus', 'newFocusKey', newFocusKey); | ||
@@ -889,3 +917,3 @@ | ||
updateFocusable(focusKey, {node, preferredChildFocusKey}) { | ||
updateFocusable(focusKey, {node, preferredChildFocusKey, focusable}) { | ||
if (this.nativeMode) { | ||
@@ -899,2 +927,3 @@ return; | ||
component.preferredChildFocusKey = preferredChildFocusKey; | ||
component.focusable = focusable; | ||
@@ -901,0 +930,0 @@ if (node) { |
@@ -102,3 +102,4 @@ /* eslint-disable react/no-find-dom-node */ | ||
onUpdateHasFocusedChild, | ||
trackChildren | ||
trackChildren, | ||
focusable = true | ||
} = this.props; | ||
@@ -119,7 +120,10 @@ | ||
forgetLastFocusedChild: (configForgetLastFocusedChild || forgetLastFocusedChild), | ||
trackChildren: (configTrackChildren || trackChildren) | ||
trackChildren: (configTrackChildren || trackChildren), | ||
focusable | ||
}); | ||
}, | ||
componentDidUpdate(prevProps) { | ||
const {focused, realFocusKey: focusKey, onBecameFocusedHandler, preferredChildFocusKey} = this.props; | ||
const { | ||
focused, realFocusKey: focusKey, onBecameFocusedHandler, preferredChildFocusKey, focusable = true | ||
} = this.props; | ||
@@ -130,3 +134,4 @@ const node = SpatialNavigation.isNativeMode() ? null : findDOMNode(this); | ||
node, | ||
preferredChildFocusKey | ||
preferredChildFocusKey, | ||
focusable | ||
}); | ||
@@ -133,0 +138,0 @@ |
4668360
3128
410
6
13
+ Addedarray-find-index@1.0.2(transitive)
+ Addedcore-js@2.6.12(transitive)
+ Addedcreate-react-class@15.7.0(transitive)
+ Addedcss-in-js-utils@2.0.1(transitive)
+ Addeddebounce@1.2.1(transitive)
+ Addeddeep-assign@3.0.0(transitive)
+ Addedfbjs@1.0.0(transitive)
+ Addedfbjs-css-vars@1.0.2(transitive)
+ Addedhyphenate-style-name@1.1.0(transitive)
+ Addedinline-style-prefixer@5.1.2(transitive)
+ Addedis-obj@1.0.1(transitive)
+ Addedisobject@3.0.1(transitive)
+ Addednormalize-css-color@1.0.2(transitive)
+ Addedreact@19.0.0(transitive)
+ Addedreact-dom@19.0.0(transitive)
+ Addedreact-native-web@0.11.7(transitive)
+ Addedreact-timer-mixin@0.13.4(transitive)
+ Addedscheduler@0.25.0(transitive)
- Removedreact@^16.5.2
- Removedreact-dom@^16.5.2
- Removedreact-dom@16.14.0(transitive)
- Removedscheduler@0.19.1(transitive)
Updatedlodash@^4.17.13