@enact/sandstone
Version:
Large-screen/TV support library for Enact, containing a variety of UI components.
157 lines (145 loc) • 5.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useSpotlightRestore = exports.useSpotlightConfig = void 0;
var _spotlight = _interopRequireDefault(require("@enact/spotlight"));
var _utilDOM = _interopRequireDefault(require("@enact/ui/useScroll/utilDOM"));
var _react = require("react");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var useSpotlightConfig = exports.useSpotlightConfig = function useSpotlightConfig(props, instances) {
// Hooks
(0, _react.useEffect)(function () {
function lastFocusedPersist() {
var lastFocusedIndex = instances.spottable.current.lastFocusedIndex;
if (lastFocusedIndex != null) {
return {
container: false,
element: true,
key: lastFocusedIndex
};
}
}
function lastFocusedRestore(_ref, all) {
var key = _ref.key;
var placeholder = all.find(function (el) {
return 'vlPlaceholder' in el.dataset;
});
if (placeholder) {
placeholder.dataset.index = key;
return placeholder;
}
return all.reduce(function (focused, node) {
return focused || Number(node.dataset.index) === key && node;
}, null);
}
function configureSpotlight() {
var spacing = props.spacing,
spotlightId = props.spotlightId;
_spotlight["default"].set(spotlightId, {
enterTo: 'last-focused',
/*
* Returns the data-index as the key for last focused
*/
lastFocusedPersist: lastFocusedPersist,
/*
* Restores the data-index into the placeholder if its the only element. Tries to find a
* matching child otherwise.
*/
lastFocusedRestore: lastFocusedRestore,
/*
* Directs spotlight focus to favor straight elements that are within range of `spacing`
* over oblique elements, like scroll buttons.
*/
obliqueMultiplier: spacing > 0 ? spacing : 1
});
}
configureSpotlight();
}, [props, instances]);
};
var getNumberValue = function getNumberValue(index) {
// using '+ operator' for string > number conversion based on performance: https://jsperf.com/convert-string-to-number-techniques/7
var number = +index;
// should return -1 if index is not a number or a negative value
return number >= 0 ? number : -1;
};
var useSpotlightRestore = exports.useSpotlightRestore = function useSpotlightRestore(props, instances, context) {
var scrollContentRef = instances.scrollContentRef,
spottable = instances.spottable;
var focusByIndex = context.focusByIndex,
getItemNode = context.getItemNode;
// Mutable value
var mutableRef = (0, _react.useRef)({
preservedIndex: false,
lastSpotlightDirection: null,
restoreLastFocused: false
});
// Hooks
(0, _react.useEffect)(restoreFocus);
// Functions
function handlePlaceholderFocus(ev) {
var placeholder = ev.currentTarget;
if (placeholder) {
var index = placeholder.dataset.index;
if (index) {
mutableRef.current.preservedIndex = getNumberValue(index);
mutableRef.current.lastSpotlightDirection = null;
mutableRef.current.restoreLastFocused = true;
}
}
}
function isPlaceholderFocused() {
var current = _spotlight["default"].getCurrent();
if (current && current.dataset.vlPlaceholder && _utilDOM["default"].containsDangerously(scrollContentRef.current, current)) {
return true;
}
return false;
}
function restoreFocus() {
if (mutableRef.current.restoreLastFocused && !isPlaceholderFocused()) {
var spotlightId = props.spotlightId,
itemNode = getItemNode(mutableRef.current.preservedIndex);
if (itemNode) {
// if we're supposed to restore focus and virtual list has positioned a set of items
// that includes lastFocusedIndex, clear the indicator
mutableRef.current.restoreLastFocused = false;
// try to focus the last focused item
spottable.current.isScrolledByJump = true;
var foundLastFocused = focusByIndex(mutableRef.current.preservedIndex, mutableRef.current.lastSpotlightDirection);
spottable.current.isScrolledByJump = false;
// but if that fails (because it isn't found or is disabled), focus the container so
// spotlight isn't lost
if (!foundLastFocused) {
mutableRef.current.restoreLastFocused = true;
_spotlight["default"].focus(spotlightId);
}
}
}
}
function handleRestoreLastFocus(_ref2) {
var firstIndex = _ref2.firstIndex,
lastIndex = _ref2.lastIndex;
if (mutableRef.current.restoreLastFocused && mutableRef.current.preservedIndex >= firstIndex && mutableRef.current.preservedIndex <= lastIndex) {
restoreFocus();
}
}
function updateStatesAndBounds(_ref3) {
var dataSize = _ref3.dataSize,
moreInfo = _ref3.moreInfo,
numOfItems = _ref3.numOfItems;
return mutableRef.current.restoreLastFocused && numOfItems > 0 && mutableRef.current.preservedIndex < dataSize && (mutableRef.current.preservedIndex < moreInfo.firstVisibleIndex || mutableRef.current.preservedIndex > moreInfo.lastVisibleIndex);
}
function setPreservedIndex(index) {
var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
mutableRef.current.preservedIndex = index;
mutableRef.current.lastSpotlightDirection = direction;
mutableRef.current.restoreLastFocused = true;
}
// Return
return {
handlePlaceholderFocus: handlePlaceholderFocus,
handleRestoreLastFocus: handleRestoreLastFocus,
setPreservedIndex: setPreservedIndex,
updateStatesAndBounds: updateStatesAndBounds
};
};