@enact/sandstone
Version:
Large-screen/TV support library for Enact, containing a variety of UI components.
694 lines (652 loc) • 33.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useEventWheel = exports.useEventVoice = exports.useEventTouch = exports.useEventMouse = exports.useEventMonitor = exports.useEventKey = exports.useEventFocus = void 0;
var _handle = require("@enact/core/handle");
var _platform = _interopRequireDefault(require("@enact/core/platform"));
var _snapshot = require("@enact/core/snapshot");
var _util = require("@enact/core/util");
var _spotlight = _interopRequireWildcard(require("@enact/spotlight"));
var _container = require("@enact/spotlight/src/container");
var _utils = require("@enact/spotlight/src/utils");
var _target = require("@enact/spotlight/src/target");
var _useScroll = require("@enact/ui/useScroll");
var _utilEvent = _interopRequireDefault(require("@enact/ui/useScroll/utilEvent"));
var _utilDOM = _interopRequireDefault(require("@enact/ui/useScroll/utilDOM"));
var _react = require("react");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
var animationDuration = _useScroll.constants.animationDuration,
epsilon = _useScroll.constants.epsilon,
isPageDown = _useScroll.constants.isPageDown,
isPageUp = _useScroll.constants.isPageUp,
overscrollTypeOnce = _useScroll.constants.overscrollTypeOnce,
paginationPageMultiplier = _useScroll.constants.paginationPageMultiplier,
scrollWheelPageMultiplierForMaxPixel = _useScroll.constants.scrollWheelPageMultiplierForMaxPixel;
var lastPointer = {
x: 0,
y: 0
};
var useEventFocus = exports.useEventFocus = function useEventFocus(props, instances) {
var scrollMode = props.scrollMode;
var scrollContainerHandle = instances.scrollContainerHandle,
scrollContainerRef = instances.scrollContainerRef,
scrollContentRef = instances.scrollContentRef,
spottable = instances.spottable,
themeScrollContentHandle = instances.themeScrollContentHandle;
// Functions
var startScrollOnFocus = function startScrollOnFocus(pos) {
if (pos) {
var top = pos.top,
left = pos.left,
bounds = scrollContainerHandle.current.getScrollBounds();
if (scrollMode === 'translate') {
var scrollHorizontally = bounds.maxLeft > 0 && left !== scrollContainerHandle.current.scrollLeft,
scrollVertically = bounds.maxTop > 0 && top !== scrollContainerHandle.current.scrollTop;
if (scrollHorizontally || scrollVertically) {
scrollContainerHandle.current.start({
targetX: left,
targetY: top,
animate: animationDuration > 0 && spottable.current.animateOnFocus,
overscrollEffect: props.overscrollEffectOn[scrollContainerHandle.current.lastInputType] && (!themeScrollContentHandle.current.shouldPreventOverscrollEffect || !themeScrollContentHandle.current.shouldPreventOverscrollEffect())
});
spottable.current.lastScrollPositionOnFocus = pos;
}
} else {
var _scrollHorizontally = bounds.maxLeft > 0 && Math.abs(left - scrollContainerHandle.current.scrollLeft) > epsilon,
_scrollVertically = bounds.maxTop > 0 && Math.abs(top - scrollContainerHandle.current.scrollTop) > epsilon;
if (_scrollHorizontally || _scrollVertically) {
scrollContainerHandle.current.start({
targetX: left,
targetY: top,
animate: spottable.current.animateOnFocus,
overscrollEffect: props.overscrollEffectOn[scrollContainerHandle.current.lastInputType] && (!themeScrollContentHandle.current.shouldPreventOverscrollEffect || !themeScrollContentHandle.current.shouldPreventOverscrollEffect())
});
spottable.current.lastScrollPositionOnFocus = pos;
}
}
}
};
function calculateAndScrollTo() {
var positionFn = themeScrollContentHandle.current.calculatePositionOnFocus,
scrollContentNode = scrollContentRef.current;
var spotItem = _spotlight["default"].getCurrent();
// Scroll to the container created by ContentContainerDecorator when descendants get focused
if (props.scrollToContentContainerOnFocus) {
spotItem = (0, _container.getPositionTargetOnFocus)(spotItem);
}
if (spotItem && positionFn && _utilDOM["default"].containsDangerously(scrollContentNode, spotItem)) {
var lastPos = spottable.current.lastScrollPositionOnFocus;
var pos;
// If scroll animation is ongoing, we need to pass last target position to
// determine correct scroll position.
if (lastPos & (scrollMode === 'translate' && scrollContainerHandle.current.animator.isAnimating() || scrollMode === 'native' && scrollContainerHandle.current.scrolling)) {
var contentRect = (0, _utils.getRect)(scrollContentNode),
itemRect = (0, _utils.getRect)(spotItem);
var scrollPosition;
if (props.direction === 'horizontal' || props.direction === 'both' && !(itemRect.left >= contentRect.left && itemRect.right <= contentRect.right)) {
scrollPosition = lastPos.left;
} else if (props.direction === 'vertical' || props.direction === 'both' && !(itemRect.top >= contentRect.top && itemRect.bottom <= contentRect.bottom)) {
scrollPosition = lastPos.top;
}
pos = positionFn({
item: spotItem,
scrollPosition: scrollPosition
});
} else {
pos = positionFn({
item: spotItem
});
}
if (pos && (pos.left !== scrollContainerHandle.current.scrollLeft || pos.top !== scrollContainerHandle.current.scrollTop)) {
startScrollOnFocus(pos);
}
// update `scrollHeight`
scrollContainerHandle.current.bounds.scrollHeight = scrollContainerHandle.current.getScrollBounds().scrollHeight;
}
}
function handleFocus(ev) {
var shouldPreventScrollByFocus = themeScrollContentHandle.current.shouldPreventScrollByFocus ? themeScrollContentHandle.current.shouldPreventScrollByFocus() : false;
if (spottable.current.isWheeling) {
scrollContainerHandle.current.stop();
if (scrollMode === 'translate') {
spottable.current.animateOnFocus = false;
}
}
if (!(shouldPreventScrollByFocus || _spotlight["default"].getPointerMode() || scrollContainerHandle.current.isDragging || spottable.current.indexToFocus)) {
var item = ev.target,
spotItem = _spotlight["default"].getCurrent();
if (item && item === spotItem) {
calculateAndScrollTo();
}
} else if (themeScrollContentHandle.current.setLastFocusedNode) {
themeScrollContentHandle.current.setLastFocusedNode(ev.target);
}
}
function hasFocus() {
var current = _spotlight["default"].getCurrent();
if (current && scrollContainerRef.current) {
return _utilDOM["default"].containsDangerously(scrollContainerRef, current);
}
}
// Return
return {
calculateAndScrollTo: calculateAndScrollTo,
handleFocus: handleFocus,
hasFocus: hasFocus
};
};
var useEventKey = exports.useEventKey = function useEventKey(props, instances, context) {
var scrollMode = props.scrollMode;
var themeScrollContentHandle = instances.themeScrollContentHandle,
spottable = instances.spottable,
scrollContentRef = instances.scrollContentRef,
scrollContainerHandle = instances.scrollContainerHandle;
var checkAndApplyOverscrollEffectByDirection = context.checkAndApplyOverscrollEffectByDirection,
hasFocus = context.hasFocus,
isContent = context.isContent;
// Functions
function handleKeyDown(ev) {
var keyCode = ev.keyCode,
repeat = ev.repeat,
target = ev.target;
(0, _handle.forward)('onKeyDown', ev, props);
if (isPageUp(keyCode) || isPageDown(keyCode)) {
ev.preventDefault();
}
spottable.current.animateOnFocus = true;
if (!repeat && hasFocus()) {
var direction = null;
if (isPageUp(keyCode) || isPageDown(keyCode)) {
if (props.direction === 'vertical' || props.direction === 'both') {
direction = isPageUp(keyCode) ? 'up' : 'down';
if (isContent(target)) {
ev.stopPropagation();
scrollByPage(direction);
}
if (props.overscrollEffectOn.pageKey) {
checkAndApplyOverscrollEffectByDirection(direction);
}
}
} else if ((0, _spotlight.getDirection)(keyCode) && (scrollMode === 'translate' || scrollMode === 'native' && !_spotlight["default"].getPointerMode())) {
var element = _spotlight["default"].getCurrent();
scrollContainerHandle.current.lastInputType = 'arrowKey';
direction = (0, _spotlight.getDirection)(keyCode);
if (props.overscrollEffectOn.arrowKey && !(element ? (0, _target.getTargetByDirectionFromElement)(direction, element) : null)) {
checkAndApplyOverscrollEffectByDirection(direction);
}
}
}
}
function scrollByPage(pageKeyDirection) {
var scrollTop = scrollContainerHandle.current.scrollTop,
focusedItem = _spotlight["default"].getCurrent(),
bounds = scrollContainerHandle.current.getScrollBounds(),
isUp = pageKeyDirection === 'up',
directionFactor = isUp ? -1 : 1,
pageDistance = directionFactor * bounds.clientHeight * paginationPageMultiplier;
var direction = pageKeyDirection;
var scrollPossible = false;
if (scrollMode === 'translate') {
scrollPossible = isUp ? scrollTop > 0 : bounds.maxTop > scrollTop;
} else {
scrollPossible = isUp ? scrollTop > 0 : bounds.maxTop - scrollTop > epsilon;
}
scrollContainerHandle.current.lastInputType = 'pageKey';
if (directionFactor !== scrollContainerHandle.current.wheelDirection) {
scrollContainerHandle.current.isScrollAnimationTargetAccumulated = false;
scrollContainerHandle.current.wheelDirection = directionFactor;
}
if (scrollPossible) {
if (focusedItem) {
var contentNode = scrollContentRef.current;
// Should do nothing when focusedItem is paging control button of Scrollbar
if (_utilDOM["default"].containsDangerously(contentNode, focusedItem)) {
var contentRect = contentNode.getBoundingClientRect(),
clientRect = focusedItem.getBoundingClientRect(),
yAdjust = isUp ? 1 : -1,
x = (0, _util.clamp)(contentRect.left, contentRect.right, (clientRect.right + clientRect.left) / 2);
var y = 0;
if (bounds.maxTop - epsilon < scrollTop + pageDistance || epsilon > scrollTop + pageDistance) {
y = contentRect[isUp ? 'top' : 'bottom'] + yAdjust;
direction = isUp ? 'down' : 'up'; // Change direction to find target in the content
} else {
y = (0, _util.clamp)(contentRect.top, contentRect.bottom, (clientRect.bottom + clientRect.top) / 2);
}
focusedItem.blur();
if (!props['data-spotlight-container-disabled']) {
themeScrollContentHandle.current.setContainerDisabled(true);
}
if (themeScrollContentHandle.current.pauseSpotlight) {
themeScrollContentHandle.current.pauseSpotlight(true);
}
spottable.current.pointToFocus = {
direction: direction,
x: x,
y: y
};
}
} else {
spottable.current.pointToFocus = {
direction: direction,
x: lastPointer.x,
y: lastPointer.y
};
}
scrollContainerHandle.current.scrollToAccumulatedTarget(pageDistance, true, props.overscrollEffectOn.pageKey);
}
}
function scrollByPageOnPointerMode(ev) {
var keyCode = ev.keyCode,
repeat = ev.repeat;
(0, _handle.forward)('onKeyDown', ev, props);
ev.preventDefault();
spottable.current.animateOnFocus = true;
if (!repeat && (props.direction === 'vertical' || props.direction === 'both')) {
var direction = isPageUp(keyCode) ? 'up' : 'down';
scrollByPage(direction);
if (props.overscrollEffectOn.pageKey) {
/* if the spotlight focus will not move */
checkAndApplyOverscrollEffectByDirection(direction);
}
return true; // means consumed
}
return false; // means to be propagated
}
// Return
return {
handleKeyDown: handleKeyDown,
lastPointer: lastPointer,
scrollByPageOnPointerMode: scrollByPageOnPointerMode
};
};
/*
* Track the last position of the pointer to check if a list should scroll by
* page up/down keys when the pointer is on a list without any focused node.
* `keydown` event does not occur if there is no focus on the node and
* its descendants, we add `keydown` handler to `document` also.
*/
var scrollers = new Map();
// An app could have lists and/or scrollers more than one,
// so we should test all of them when page up/down key is pressed.
var pointerTracker = function pointerTracker(ev) {
lastPointer.x = ev.clientX;
lastPointer.y = ev.clientY;
};
var pageKeyHandler = function pageKeyHandler(ev) {
var keyCode = ev.keyCode;
if (_spotlight["default"].getPointerMode() && !_spotlight["default"].getCurrent() && (isPageUp(keyCode) || isPageDown(keyCode))) {
var _lastPointer = lastPointer,
x = _lastPointer.x,
y = _lastPointer.y,
elem = document.elementFromPoint(x, y);
if (elem) {
var _iterator = _createForOfIteratorHelper(scrollers),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _step$value = _slicedToArray(_step.value, 2),
key = _step$value[0],
value = _step$value[1];
if (_utilDOM["default"].containsDangerously(value, elem)) {
/* To handle page keys in nested scrollable components,
* break the loop only when `scrollByPageOnPointerMode` returns `true`.
* This approach assumes that an inner scrollable component is
* mounted earlier than an outer scrollable component.
*/
if (key.scrollByPageOnPointerMode(ev)) {
break;
}
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
}
};
var useEventMonitor = exports.useEventMonitor = function useEventMonitor(props, instances, context) {
var scrollContainerRef = instances.scrollContainerRef;
var lastPointerProp = context.lastPointer,
scrollByPageOnPointerMode = context.scrollByPageOnPointerMode;
// Mutable value
var mutableRef = (0, _react.useRef)({
pageKeyHandlerObj: {
scrollByPageOnPointerMode: scrollByPageOnPointerMode
}
});
lastPointer = lastPointerProp;
// Hooks
(0, _react.useEffect)(function () {
var setMonitorEventTarget = function setMonitorEventTarget(target) {
scrollers.set(mutableRef.current.pageKeyHandlerObj, target);
};
var deleteMonitorEventTarget = function deleteMonitorEventTarget() {
scrollers["delete"](mutableRef.current.pageKeyHandlerObj);
};
setMonitorEventTarget(scrollContainerRef.current);
return function () {
// TODO: Replace `this` to something.
deleteMonitorEventTarget();
};
}, [scrollContainerRef]);
};
(0, _snapshot.onWindowReady)(function () {
(0, _utilEvent["default"])('mousemove').addEventListener(document, pointerTracker);
(0, _utilEvent["default"])('keydown').addEventListener(document, pageKeyHandler);
});
var useEventMouse = exports.useEventMouse = function useEventMouse(props, instances) {
var scrollMode = props.scrollMode;
var themeScrollContentHandle = instances.themeScrollContentHandle,
scrollContainerHandle = instances.scrollContainerHandle;
// Functions
function handleFlick(_ref) {
var direction = _ref.direction;
var _scrollContainerHandl = scrollContainerHandle.current,
canScrollHorizontally = _scrollContainerHandl.canScrollHorizontally,
canScrollVertically = _scrollContainerHandl.canScrollVertically,
bounds = scrollContainerHandle.current.getScrollBounds(),
focusedItem = _spotlight["default"].getCurrent();
if (focusedItem) {
focusedItem.blur();
}
if ((direction === 'vertical' && canScrollVertically(bounds) || direction === 'horizontal' && canScrollHorizontally(bounds)) && !props['data-spotlight-container-disabled']) {
themeScrollContentHandle.current.setContainerDisabled(true);
}
}
function handleMouseDown(ev) {
if (props['data-spotlight-container-disabled']) {
ev.preventDefault();
} else if (scrollMode === 'native') {
themeScrollContentHandle.current.setContainerDisabled(false);
}
}
// Return
return {
handleFlick: handleFlick,
handleMouseDown: handleMouseDown
};
};
var useEventTouch = exports.useEventTouch = function useEventTouch() {
// Functions
function handleTouchStart() {
var focusedItem = _spotlight["default"].getCurrent();
if (!_spotlight["default"].isPaused() && focusedItem) {
focusedItem.blur();
}
}
// Return
return {
handleTouchStart: handleTouchStart
};
};
var useEventVoice = exports.useEventVoice = function useEventVoice(props, instances) {
var scrollContainerRef = instances.scrollContainerRef,
scrollContainerHandle = instances.scrollContainerHandle;
// Mutable value
var mutableRef = (0, _react.useRef)({
isVoiceControl: false,
voiceControlDirection: 'vertical'
});
// Functions
var updateFocusAfterVoiceControl = function updateFocusAfterVoiceControl() {
var spotItem = _spotlight["default"].getCurrent(),
scrollContainerNode = scrollContainerRef.current;
if (spotItem) {
if (_utilDOM["default"].containsDangerously(scrollContainerNode, spotItem)) {
var viewportBounds = scrollContainerNode.getBoundingClientRect();
var spotItemBounds = spotItem.getBoundingClientRect();
var isVertical = mutableRef.current.voiceControlDirection === 'vertical';
var first = isVertical ? 'top' : 'left';
var last = isVertical ? 'bottom' : 'right';
/* if the focused element is out of the viewport, find another spottable element in the viewport */
if (spotItemBounds[last] <= viewportBounds[first] || spotItemBounds[first] >= viewportBounds[last]) {
var nodes = (0, _container.getDeepSpottableDescendants)(scrollContainerNode.dataset.spotlightId);
for (var i = 0; i < nodes.length; i++) {
var nodeBounds = nodes[i].getBoundingClientRect();
if (nodeBounds[first] >= viewportBounds[first] && nodeBounds[last] <= viewportBounds[last]) {
_spotlight["default"].focus(nodes[i]);
break;
}
}
}
}
} else if (scrollContainerNode) {
// There should be an element that receives focus even if spot Item disappears from the virtuallist or scroller
var backupNodes = (0, _container.getDeepSpottableDescendants)(scrollContainerNode.dataset.spotlightId);
_spotlight["default"].focus(backupNodes[0]);
}
};
function stopVoice() {
if (mutableRef.current.isVoiceControl) {
mutableRef.current.isVoiceControl = false;
updateFocusAfterVoiceControl();
}
}
var isReachedEdge = function isReachedEdge(scrollPos, ltrBound, rtlBound) {
var isRtl = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var bound = isRtl ? rtlBound : ltrBound;
return bound === 0 && scrollPos === 0 || bound > 0 && scrollPos >= bound - 1;
};
var handleVoice = function handleVoice(e) {
var isHorizontal = props.direction === 'horizontal',
isRtl = scrollContainerHandle.current.rtl,
_scrollContainerHandl2 = scrollContainerHandle.current,
scrollTop = _scrollContainerHandl2.scrollTop,
scrollLeft = _scrollContainerHandl2.scrollLeft,
_scrollContainerHandl3 = scrollContainerHandle.current.getScrollBounds(),
maxLeft = _scrollContainerHandl3.maxLeft,
maxTop = _scrollContainerHandl3.maxTop,
verticalDirection = ['up', 'down', 'top', 'bottom'],
horizontalDirection = isRtl ? ['right', 'left', 'rightmost', 'leftmost'] : ['left', 'right', 'leftmost', 'rightmost'],
movement = ['previous', 'next', 'first', 'last'];
var scroll = e && e.detail && e.detail.scroll,
index = movement.indexOf(scroll);
if (index > -1) {
scroll = isHorizontal ? horizontalDirection[index] : verticalDirection[index];
}
mutableRef.current.voiceControlDirection = verticalDirection.includes(scroll) && 'vertical' || horizontalDirection.includes(scroll) && 'horizontal' || null;
// Case 1. Invalid direction
if (mutableRef.current.voiceControlDirection === null) {
mutableRef.current.isVoiceControl = false;
// Case 2. Cannot scroll
} else if (['up', 'top'].includes(scroll) && isReachedEdge(scrollTop, 0) || ['down', 'bottom'].includes(scroll) && isReachedEdge(scrollTop, maxTop) || ['left', 'leftmost'].includes(scroll) && isReachedEdge(scrollLeft, 0, maxLeft, isRtl) || ['right', 'rightmost'].includes(scroll) && isReachedEdge(scrollLeft, maxLeft, 0, isRtl)) {
if (window.webOSVoiceReportActionResult) {
window.webOSVoiceReportActionResult({
voiceUi: {
exception: 'alreadyCompleted'
}
});
e.preventDefault();
}
// Case 3. Can scroll
} else {
mutableRef.current.isVoiceControl = true;
if (['up', 'down', 'left', 'right'].includes(scroll)) {
var bounds = scrollContainerHandle.current.getScrollBounds(),
directionFactor = scroll === 'up' || scroll === 'left' && !isRtl || scroll === 'right' && isRtl,
scrollVertically = verticalDirection.includes(scroll),
direction = directionFactor ? -1 : 1,
pageDistance = direction * (scrollVertically ? bounds.clientHeight : bounds.clientWidth) * paginationPageMultiplier;
scrollContainerHandle.current.lastInputType = 'pageKey';
if (direction !== scrollContainerHandle.current.wheelDirection) {
scrollContainerHandle.current.isScrollAnimationTargetAccumulated = false;
scrollContainerHandle.current.wheelDirection = direction;
}
scrollContainerHandle.current.scrollToAccumulatedTarget(pageDistance, scrollVertically, props.overscrollEffectOn.pageKey);
} else {
// ['top', 'bottom', 'leftmost', 'rightmost'].includes(scroll)
scrollContainerHandle.current.scrollTo({
align: verticalDirection.includes(scroll) && scroll || (scroll === 'leftmost' && isRtl || scroll === 'rightmost' && !isRtl) && 'right' || 'left'
});
}
e.preventDefault();
}
};
function addVoiceEventListener(scrollContentRef) {
if (_platform["default"].type === 'webos') {
(0, _utilEvent["default"])('webOSVoice').addEventListener(scrollContentRef, handleVoice);
if (scrollContainerHandle && scrollContainerHandle.current && scrollContainerHandle.current.getScrollBounds) {
var bounds = scrollContainerHandle.current.getScrollBounds();
if (scrollContainerHandle.current.canScrollVertically(bounds) || scrollContainerHandle.current.canScrollHorizontally(bounds)) {
scrollContentRef.current.setAttribute('data-webos-voice-intent', 'Scroll');
}
}
}
}
function removeVoiceEventListener(scrollContentRef) {
if (_platform["default"].type === 'webos') {
(0, _utilEvent["default"])('webOSVoice').removeEventListener(scrollContentRef, handleVoice);
scrollContentRef.current.removeAttribute('data-webos-voice-intent');
}
}
// Return
return {
addVoiceEventListener: addVoiceEventListener,
removeVoiceEventListener: removeVoiceEventListener,
stopVoice: stopVoice
};
};
var useEventWheel = exports.useEventWheel = function useEventWheel(props, instances) {
var dataSize = props.dataSize,
scrollMode = props.scrollMode,
snapToCenter = props.snapToCenter;
var themeScrollContentHandle = instances.themeScrollContentHandle,
scrollContainerHandle = instances.scrollContainerHandle,
scrollContentHandle = instances.scrollContentHandle,
scrollContentRef = instances.scrollContentRef,
spottable = instances.spottable;
// Functions
function initializeWheeling() {
if (!props['data-spotlight-container-disabled']) {
themeScrollContentHandle.current.setContainerDisabled(true);
}
spottable.current.isWheeling = true;
}
function handleWheel(_ref2) {
var delta = _ref2.delta;
var focusedItem = _spotlight["default"].getCurrent();
if (focusedItem) {
focusedItem.blur();
}
if (delta !== 0) {
initializeWheeling();
}
}
/*
* wheel event handler;
* - for horizontal scroll, supports wheel action on any children nodes since web engine cannot support this
* - for vertical scroll, supports wheel action on scrollbars only
*/
function handleWheelNative(ev) {
var overscrollEffectRequired = props.overscrollEffectOn.wheel;
var bounds = scrollContainerHandle.current.getScrollBounds();
var canScrollHorizontally = scrollContainerHandle.current.canScrollHorizontally(bounds);
var canScrollVertically = scrollContainerHandle.current.canScrollVertically(bounds);
var eventDeltaMode = ev.deltaMode;
var eventDelta = -ev.wheelDeltaY || ev.deltaY;
var positiveDelta = eventDelta > 0;
var negativeDelta = eventDelta < 0;
var _scrollContainerHandl4 = scrollContainerHandle.current,
scrollTop = _scrollContainerHandl4.scrollTop,
scrollLeft = _scrollContainerHandl4.scrollLeft;
var offset = snapToCenter ? scrollContentHandle.current.primary.gridSize : 0;
var delta = 0;
var needToHideScrollbarTrack = false;
if (typeof window !== 'undefined') {
window.document.activeElement.blur();
}
scrollContainerHandle.current.showScrollbarTrack(bounds);
// FIXME This routine is a temporary support for horizontal wheel scroll.
// FIXME If web engine supports horizontal wheel, this routine should be refined or removed.
if (canScrollVertically) {
// This routine handles wheel events on scrollbars for vertical scroll.
if (negativeDelta && scrollTop > 0 + offset || positiveDelta && scrollTop < bounds.maxTop - offset) {
if (!spottable.current.isWheeling) {
initializeWheeling();
}
// If ev.target is a descendant of scrollContent, the event will be handled on scroll event handler.
if (!_utilDOM["default"].containsDangerously(scrollContentRef.current, ev.target) || snapToCenter) {
delta = scrollContainerHandle.current.calculateDistanceByWheel(eventDeltaMode, eventDelta, bounds.clientHeight * scrollWheelPageMultiplierForMaxPixel);
needToHideScrollbarTrack = !delta;
ev.preventDefault();
} else if (overscrollEffectRequired) {
scrollContainerHandle.current.checkAndApplyOverscrollEffect('vertical', positiveDelta ? 'after' : 'before', overscrollTypeOnce);
}
ev.stopPropagation();
} else {
if (overscrollEffectRequired && (negativeDelta && scrollTop <= 0 || positiveDelta && scrollTop >= bounds.maxTop)) {
scrollContainerHandle.current.applyOverscrollEffect('vertical', positiveDelta ? 'after' : 'before', overscrollTypeOnce);
}
needToHideScrollbarTrack = true;
}
} else if (canScrollHorizontally) {
// this routine handles wheel events on any children for horizontal scroll.
if (negativeDelta && scrollLeft > 0 + offset || positiveDelta && scrollLeft < bounds.maxLeft - offset) {
if (!spottable.current.isWheeling) {
initializeWheeling();
}
delta = scrollContainerHandle.current.calculateDistanceByWheel(eventDeltaMode, eventDelta, bounds.clientWidth * scrollWheelPageMultiplierForMaxPixel);
needToHideScrollbarTrack = !delta;
ev.preventDefault();
ev.stopPropagation();
} else {
if (overscrollEffectRequired && (negativeDelta && scrollLeft <= 0 || positiveDelta && scrollLeft >= bounds.maxLeft)) {
scrollContainerHandle.current.applyOverscrollEffect('horizontal', positiveDelta ? 'after' : 'before', overscrollTypeOnce);
}
needToHideScrollbarTrack = true;
}
}
if (delta !== 0) {
/* prevent native scrolling feature for vertical direction */
ev.preventDefault();
var direction = Math.sign(delta);
// Not to accumulate scroll position if wheel direction is different from hold direction
if (direction !== scrollContainerHandle.current.wheelDirection) {
scrollContainerHandle.current.isScrollAnimationTargetAccumulated = false;
scrollContainerHandle.current.wheelDirection = direction;
}
if (!snapToCenter) {
scrollContainerHandle.current.scrollToAccumulatedTarget(delta, canScrollVertically, overscrollEffectRequired);
} else {
var dimensionToExtent = scrollContentHandle.current.dimensionToExtent;
var currentIndex = scrollContentHandle.current.getCenterItemIndexFromScrollPosition(canScrollVertically ? scrollTop : scrollLeft);
var nextIndex = currentIndex + direction * dimensionToExtent;
if (nextIndex > 0 && nextIndex < dataSize - 1) {
if (typeof document === 'object') {
var target = scrollContentRef.current.querySelector("[data-index=\"".concat(nextIndex, "\"] > div"));
// remove effect
themeScrollContentHandle.current.removeScaleEffect();
// add effect
themeScrollContentHandle.current.addScaleEffect(target);
}
if (themeScrollContentHandle.current.resetSnapToCenterStatus) {
themeScrollContentHandle.current.resetSnapToCenterStatus();
}
scrollContainerHandle.current.scrollTo({
index: nextIndex,
stickTo: 'center'
});
}
}
}
if (needToHideScrollbarTrack) {
scrollContainerHandle.current.startHidingScrollbarTrack();
}
}
// Return
return {
handleWheel: scrollMode === 'translate' ? handleWheel : handleWheelNative
};
};