@noriginmedia/react-spatial-navigation
Version:
HOC-based Spatial Navigation (key navigation) solution for React
272 lines (218 loc) • 10.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _reactDom = require('react-dom');
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _uniqueId = require('lodash/uniqueId');
var _uniqueId2 = _interopRequireDefault(_uniqueId);
var _noop = require('lodash/noop');
var _noop2 = _interopRequireDefault(_noop);
var _omit = require('lodash/omit');
var _omit2 = _interopRequireDefault(_omit);
var _compose = require('recompose/compose');
var _compose2 = _interopRequireDefault(_compose);
var _lifecycle = require('recompose/lifecycle');
var _lifecycle2 = _interopRequireDefault(_lifecycle);
var _withHandlers = require('recompose/withHandlers');
var _withHandlers2 = _interopRequireDefault(_withHandlers);
var _withContext = require('recompose/withContext');
var _withContext2 = _interopRequireDefault(_withContext);
var _withStateHandlers = require('recompose/withStateHandlers');
var _withStateHandlers2 = _interopRequireDefault(_withStateHandlers);
var _getContext = require('recompose/getContext');
var _getContext2 = _interopRequireDefault(_getContext);
var _pure = require('recompose/pure');
var _pure2 = _interopRequireDefault(_pure);
var _mapProps = require('recompose/mapProps');
var _mapProps2 = _interopRequireDefault(_mapProps);
var _spatialNavigation = require('./spatialNavigation');
var _spatialNavigation2 = _interopRequireDefault(_spatialNavigation);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /* eslint-disable react/no-find-dom-node */
var omitProps = function omitProps(keys) {
return (0, _mapProps2.default)(function (props) {
return (0, _omit2.default)(props, keys);
});
};
var withFocusable = function withFocusable() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$forgetLastFocuse = _ref.forgetLastFocusedChild,
configForgetLastFocusedChild = _ref$forgetLastFocuse === undefined ? false : _ref$forgetLastFocuse,
_ref$trackChildren = _ref.trackChildren,
configTrackChildren = _ref$trackChildren === undefined ? false : _ref$trackChildren,
configAutoRestoreFocus = _ref.autoRestoreFocus,
_ref$blockNavigationO = _ref.blockNavigationOut,
configBlockNavigationOut = _ref$blockNavigationO === undefined ? false : _ref$blockNavigationO;
return (0, _compose2.default)((0, _getContext2.default)({
/**
* From the context provided by another higher-level 'withFocusable' component
*/
parentFocusKey: _propTypes2.default.string
}), (0, _withStateHandlers2.default)(function (_ref2) {
var focusKey = _ref2.focusKey,
parentFocusKey = _ref2.parentFocusKey;
var realFocusKey = focusKey || (0, _uniqueId2.default)('sn:focusable-item-');
return {
realFocusKey: realFocusKey,
/**
* This method is used to imperatively set focus to a component.
* It is blocked in the Native mode because the native engine decides what to focus by itself.
*/
setFocus: _spatialNavigation2.default.isNativeMode() ? _noop2.default : _spatialNavigation2.default.setFocus.bind(null, realFocusKey),
navigateByDirection: _spatialNavigation2.default.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.
*/
stealFocus: _spatialNavigation2.default.setFocus.bind(null, realFocusKey, realFocusKey),
focused: false,
hasFocusedChild: false,
parentFocusKey: parentFocusKey || _spatialNavigation.ROOT_FOCUS_KEY
};
}, {
onUpdateFocus: function onUpdateFocus() {
return function () {
var focused = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
return {
focused: focused
};
};
},
onUpdateHasFocusedChild: function onUpdateHasFocusedChild() {
return function () {
var hasFocusedChild = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
return {
hasFocusedChild: hasFocusedChild
};
};
}
}),
/**
* Propagate own 'focusKey' as a 'parentFocusKey' to it's children
*/
(0, _withContext2.default)({
parentFocusKey: _propTypes2.default.string
}, function (_ref3) {
var realFocusKey = _ref3.realFocusKey;
return {
parentFocusKey: realFocusKey
};
}), (0, _withHandlers2.default)({
onEnterPressHandler: function onEnterPressHandler(_ref4) {
var _ref4$onEnterPress = _ref4.onEnterPress,
onEnterPress = _ref4$onEnterPress === undefined ? _noop2.default : _ref4$onEnterPress,
rest = _objectWithoutProperties(_ref4, ['onEnterPress']);
return function (details) {
onEnterPress(rest, details);
};
},
onEnterReleaseHandler: function onEnterReleaseHandler(_ref5) {
var _ref5$onEnterRelease = _ref5.onEnterRelease,
onEnterRelease = _ref5$onEnterRelease === undefined ? _noop2.default : _ref5$onEnterRelease,
rest = _objectWithoutProperties(_ref5, ['onEnterRelease']);
return function () {
onEnterRelease(rest);
};
},
onArrowPressHandler: function onArrowPressHandler(_ref6) {
var _ref6$onArrowPress = _ref6.onArrowPress,
onArrowPress = _ref6$onArrowPress === undefined ? _noop2.default : _ref6$onArrowPress,
rest = _objectWithoutProperties(_ref6, ['onArrowPress']);
return function (direction, details) {
return onArrowPress(direction, rest, details);
};
},
onBecameFocusedHandler: function onBecameFocusedHandler(_ref7) {
var _ref7$onBecameFocused = _ref7.onBecameFocused,
onBecameFocused = _ref7$onBecameFocused === undefined ? _noop2.default : _ref7$onBecameFocused,
rest = _objectWithoutProperties(_ref7, ['onBecameFocused']);
return function (layout, details) {
onBecameFocused(layout, rest, details);
};
},
onBecameBlurredHandler: function onBecameBlurredHandler(_ref8) {
var _ref8$onBecameBlurred = _ref8.onBecameBlurred,
onBecameBlurred = _ref8$onBecameBlurred === undefined ? _noop2.default : _ref8$onBecameBlurred,
rest = _objectWithoutProperties(_ref8, ['onBecameBlurred']);
return function (layout, details) {
onBecameBlurred(layout, rest, details);
};
},
pauseSpatialNavigation: function pauseSpatialNavigation() {
return _spatialNavigation2.default.pause;
},
resumeSpatialNavigation: function resumeSpatialNavigation() {
return _spatialNavigation2.default.resume;
},
updateAllSpatialLayouts: function updateAllSpatialLayouts() {
return _spatialNavigation2.default.updateAllLayouts;
}
}), (0, _lifecycle2.default)({
componentDidMount: function componentDidMount() {
var _props = this.props,
focusKey = _props.realFocusKey,
parentFocusKey = _props.parentFocusKey,
preferredChildFocusKey = _props.preferredChildFocusKey,
_props$forgetLastFocu = _props.forgetLastFocusedChild,
forgetLastFocusedChild = _props$forgetLastFocu === undefined ? false : _props$forgetLastFocu,
onEnterPressHandler = _props.onEnterPressHandler,
onEnterReleaseHandler = _props.onEnterReleaseHandler,
onArrowPressHandler = _props.onArrowPressHandler,
onBecameFocusedHandler = _props.onBecameFocusedHandler,
onBecameBlurredHandler = _props.onBecameBlurredHandler,
onUpdateFocus = _props.onUpdateFocus,
onUpdateHasFocusedChild = _props.onUpdateHasFocusedChild,
trackChildren = _props.trackChildren,
_props$focusable = _props.focusable,
focusable = _props$focusable === undefined ? true : _props$focusable,
_props$autoRestoreFoc = _props.autoRestoreFocus,
autoRestoreFocus = _props$autoRestoreFoc === undefined ? true : _props$autoRestoreFoc,
_props$blockNavigatio = _props.blockNavigationOut,
blockNavigationOut = _props$blockNavigatio === undefined ? false : _props$blockNavigatio;
var node = _spatialNavigation2.default.isNativeMode() ? this : (0, _reactDom.findDOMNode)(this);
_spatialNavigation2.default.addFocusable({
focusKey: focusKey,
node: node,
parentFocusKey: parentFocusKey,
preferredChildFocusKey: preferredChildFocusKey,
onEnterPressHandler: onEnterPressHandler,
onEnterReleaseHandler: onEnterReleaseHandler,
onArrowPressHandler: onArrowPressHandler,
onBecameFocusedHandler: onBecameFocusedHandler,
onBecameBlurredHandler: onBecameBlurredHandler,
onUpdateFocus: onUpdateFocus,
onUpdateHasFocusedChild: onUpdateHasFocusedChild,
forgetLastFocusedChild: configForgetLastFocusedChild || forgetLastFocusedChild,
trackChildren: configTrackChildren || trackChildren,
blockNavigationOut: configBlockNavigationOut || blockNavigationOut,
autoRestoreFocus: configAutoRestoreFocus !== undefined ? configAutoRestoreFocus : autoRestoreFocus,
focusable: focusable
});
},
componentDidUpdate: function componentDidUpdate() {
var _props2 = this.props,
focusKey = _props2.realFocusKey,
preferredChildFocusKey = _props2.preferredChildFocusKey,
_props2$focusable = _props2.focusable,
focusable = _props2$focusable === undefined ? true : _props2$focusable,
_props2$blockNavigati = _props2.blockNavigationOut,
blockNavigationOut = _props2$blockNavigati === undefined ? false : _props2$blockNavigati;
var node = _spatialNavigation2.default.isNativeMode() ? this : (0, _reactDom.findDOMNode)(this);
_spatialNavigation2.default.updateFocusable(focusKey, {
node: node,
preferredChildFocusKey: preferredChildFocusKey,
focusable: focusable,
blockNavigationOut: configBlockNavigationOut || blockNavigationOut
});
},
componentWillUnmount: function componentWillUnmount() {
var focusKey = this.props.realFocusKey;
_spatialNavigation2.default.removeFocusable({
focusKey: focusKey
});
}
}), _pure2.default, omitProps(['onBecameFocusedHandler', 'onBecameBlurredHandler', 'onEnterPressHandler', 'onEnterReleaseHandler', 'onArrowPressHandler', 'onUpdateFocus', 'onUpdateHasFocusedChild', 'forgetLastFocusedChild', 'trackChildren', 'autoRestoreFocus']));
};
exports.default = withFocusable;