UNPKG

@enact/sandstone

Version:

Large-screen/TV support library for Enact, containing a variety of UI components.

694 lines (652 loc) 33.6 kB
"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 }; };