UNPKG

@enact/sandstone

Version:

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

980 lines (960 loc) 51.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = exports.EditableWrapper = exports.EditableShape = void 0; var _handle = require("@enact/core/handle"); var _propTypes = _interopRequireDefault(require("@enact/core/internal/prop-types")); var _keymap = require("@enact/core/keymap"); var _usePublicClassNames = require("@enact/core/usePublicClassNames"); var _spotlight = _interopRequireWildcard(require("@enact/spotlight")); var _container = require("@enact/spotlight/src/container"); var _target = require("@enact/spotlight/src/target"); var _Accelerator = _interopRequireDefault(require("@enact/spotlight/Accelerator")); var _pointer = require("@enact/spotlight/src/pointer"); var _AnnounceDecorator = require("@enact/ui/AnnounceDecorator"); var _Touchable = _interopRequireDefault(require("@enact/ui/Touchable")); var _classnames = _interopRequireDefault(require("classnames")); var _IString = _interopRequireDefault(require("ilib/lib/IString")); var _propTypes2 = _interopRequireDefault(require("prop-types")); var _react = require("react"); var _$L = _interopRequireDefault(require("../internal/$L")); var _EditableWrapperModule = _interopRequireDefault(require("./EditableWrapper.module.css")); var _jsxRuntime = require("react/jsx-runtime"); 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 _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var completeAnnounceDelay = 300; // An arbitrary delay at a level that is not ignored by the new focus element var TouchableDiv = (0, _Touchable["default"])('div'); /** * The shape for editable of {@link sandstone/Scroller|Scroller}. * * @typedef {Object} EditableShape * @memberof sandstone/Scroller * @property {Function} onComplete The callback function called when editing is finished. * It has an event object contains `orders` array which app can use for repopulate items. * @property {Function|Object} [blurItemFuncRef] Obtains a reference to `blurItem` function. * If you would like to remove `focused` CSS class to an item, you can get the reference to `blurItem` function via `useRef`. * `blurItem` function needs to be called with an item node when an item is blurred. * @property {Boolean} [centered] Centers the contents of the scroller. * @property {Object} [css] Customizes the component by mapping the supplied collection of CSS class names to the * corresponding internal elements and states of this component. * The following classes are supported: * * * `wrapper` - The content wrapper component class * * `selected` - The selected item class * * `focused` - The focused item class * @property {Function|Object} [focusItemFuncRef] Obtains a reference to `focusItem` function. * If you would like to use `focused` CSS class to an item, you can get the reference to `focusItem` function via `useRef`. * `focusItem` function needs to be called with an item node when an item is focused. * @property {Function|Object} [hideItemFuncRef] Obtains a reference to `hideItem` function. * If you would like to hide an item, you can get the reference to `hideItem` function via `useRef`. * @property {Function|Object} [removeItemFuncRef] Obtains a reference to `removeItem` function. * If you would like to remove an item, you can get the reference to `removeItem` function via `useRef`. * @property {string} [selectItemBy] Decides how to start editing items. * It can be either `'press'` or `'longPress'`. If unset, it defaults to `'longPress'`. * @property {Function|Object} [showItemFuncRef] Obtains a reference to `showItem` function. * If you would like to show an item, you can get the reference to `showItem` function via `useRef`. * @public */ var EditableShape = exports.EditableShape = _propTypes2["default"].shape({ onComplete: _propTypes2["default"].func.isRequired, blurItemFuncRef: _propTypes["default"].ref, centered: _propTypes2["default"].bool, css: _propTypes2["default"].object, focusItemFuncRef: _propTypes["default"].ref, hideItemFuncRef: _propTypes["default"].ref, removeItemFuncRef: _propTypes["default"].ref, selectItemBy: _propTypes2["default"].string, showItemFuncRef: _propTypes["default"].ref }); var SpotlightAccelerator = new _Accelerator["default"]([5, 4]); var holdDuration = 500; var holdConfig = { events: [{ name: 'hold', time: holdDuration }] }; /** * A Sandstone-styled EditableWrapper. * * @class EditableWrapper * @memberof sandstone/Scroller * @ui * @public */ var EditableWrapper = exports.EditableWrapper = function EditableWrapper(props) { var _editable$hideIndex; var children = props.children, editable = props.editable, scrollContainerHandle = props.scrollContainerHandle, scrollContainerRef = props.scrollContainerRef, scrollContentRef = props.scrollContentRef; var centered = (editable === null || editable === void 0 ? void 0 : editable.centered) != null ? editable.centered : true; var selectItemBy = (editable === null || editable === void 0 ? void 0 : editable.selectItemBy) || 'longPress'; var customCss = (editable === null || editable === void 0 ? void 0 : editable.css) || {}; var removeItemFuncRef = editable === null || editable === void 0 ? void 0 : editable.removeItemFuncRef; var hideItemFuncRef = editable === null || editable === void 0 ? void 0 : editable.hideItemFuncRef; var showItemFuncRef = editable === null || editable === void 0 ? void 0 : editable.showItemFuncRef; var focusItemFuncRef = editable === null || editable === void 0 ? void 0 : editable.focusItemFuncRef; var blurItemFuncRef = editable === null || editable === void 0 ? void 0 : editable.blurItemFuncRef; var mergedCss = (0, _usePublicClassNames.usePublicClassNames)({ componentCss: _EditableWrapperModule["default"], customCss: customCss, publicClassNames: true }); var dataSize = children === null || children === void 0 ? void 0 : children.length; // Mutable value var wrapperRef = (0, _react.useRef)(); var mutableRef = (0, _react.useRef)({ // Constants itemWidth: null, centeredOffset: 0, spotlightId: null, // DOM elements focusedItem: null, selectedItem: null, selectedItemLabel: '', rearrangedItems: [], // Indices fromIndex: null, prevToIndex: null, hideIndex: null, // Position for restoring focus after removing item nextSpotlightRect: null, // Move direction from the starting position to the current position moveDirection: null, // Last mouse position lastMouseClientX: null, // Last InputType lastInputType: null, // Timer for holding key input keyHoldTimerId: null, // Flag for prevent event propagation needToPreventEvent: null, lastInputDirection: null, isDraggingItem: false, isDragging: false, // initialSelected initialSelected: editable === null || editable === void 0 ? void 0 : editable.initialSelected }); var announceRef = (0, _react.useRef)({}); mutableRef.current.hideIndex = (_editable$hideIndex = editable === null || editable === void 0 ? void 0 : editable.hideIndex) !== null && _editable$hideIndex !== void 0 ? _editable$hideIndex : dataSize; // Functions // Reset values var reset = (0, _react.useCallback)(function () { var _mutableRef$current = mutableRef.current, focusedItem = _mutableRef$current.focusedItem, selectedItem = _mutableRef$current.selectedItem, spotlightId = _mutableRef$current.spotlightId; focusedItem === null || focusedItem === void 0 || focusedItem.classList.remove(customCss.focused); selectedItem === null || selectedItem === void 0 || selectedItem.classList.remove(_EditableWrapperModule["default"].selected, customCss.selected, _EditableWrapperModule["default"].rearranged); mutableRef.current.focusedItem = null; mutableRef.current.selectedItem = null; mutableRef.current.selectedItemLabel = ''; mutableRef.current.moveDirection = null; mutableRef.current.prevToIndex = null; mutableRef.current.initialSelected = null; wrapperRef.current.style.setProperty('--selected-item-offset', '0px'); _spotlight["default"].set(spotlightId, { restrict: 'self-first' }); }, [customCss.focused, customCss.selected]); // Finalize the order var finalizeOrders = (0, _react.useCallback)(function () { var _mutableRef$current2 = mutableRef.current, fromIndex = _mutableRef$current2.fromIndex, moveDirection = _mutableRef$current2.moveDirection, prevToIndex = _mutableRef$current2.prevToIndex, rearrangedItems = _mutableRef$current2.rearrangedItems, selectedItem = _mutableRef$current2.selectedItem; var orders = Array.from({ length: dataSize }, function (_, i) { return i + 1; }); if (rearrangedItems.length > 0) { var selectedOrder = selectedItem.style.order; var changedOrder = []; rearrangedItems.forEach(function (item) { var order = Number(item.style.order); selectedOrder = order; item.style.order = order - moveDirection; item.classList.remove(_EditableWrapperModule["default"].rearrangedTransform, _EditableWrapperModule["default"].rearranged); if (moveDirection > 0) { changedOrder.push(order); } else { changedOrder.unshift(order); } }); if (moveDirection > 0) { changedOrder.push(Number(selectedItem.style.order)); } else { changedOrder.unshift(Number(selectedItem.style.order)); } mutableRef.current.rearrangedItems = []; selectedItem.style.order = selectedOrder; // Create reordered array orders.splice.apply(orders, [Math.min(fromIndex, prevToIndex), changedOrder.length].concat(changedOrder)); } return orders; }, [dataSize]); var updateArrowIcon = (0, _react.useCallback)(function (index) { var _mutableRef$current$s, _mutableRef$current$s2; (_mutableRef$current$s = mutableRef.current.selectedItem) === null || _mutableRef$current$s === void 0 || _mutableRef$current$s.classList.toggle(customCss.noBefore, index === 0); (_mutableRef$current$s2 = mutableRef.current.selectedItem) === null || _mutableRef$current$s2 === void 0 || _mutableRef$current$s2.classList.toggle(customCss.noAfter, index === mutableRef.current.hideIndex - 1); }, [customCss.noBefore, customCss.noAfter]); var startEditing = (0, _react.useCallback)(function (item) { var _item$dataset; if (item !== null && item !== void 0 && (_item$dataset = item.dataset) !== null && _item$dataset !== void 0 && _item$dataset.index && (!item.hasAttribute('disabled') || item.className.includes('hidden'))) { var _mutableRef$current$f; item.classList.add(_EditableWrapperModule["default"].selected, customCss.selected); mutableRef.current.selectedItem = item; (_mutableRef$current$f = mutableRef.current.focusedItem) === null || _mutableRef$current$f === void 0 || _mutableRef$current$f.classList.remove(customCss.focused); mutableRef.current.focusedItem = null; mutableRef.current.selectedItemLabel = (item.ariaLabel || item.textContent) + ' '; mutableRef.current.fromIndex = Number(item.style.order) - 1; mutableRef.current.prevToIndex = mutableRef.current.fromIndex; updateArrowIcon(mutableRef.current.fromIndex); setTimeout(function () { if (item !== null && item !== void 0 && item.children[1]) { item.children[1].ariaLabel = ''; } if (!mutableRef.current.initialSelected) { announceRef.current.announce(mutableRef.current.selectedItemLabel + (0, _$L["default"])('Press the left/right button to move or press the up button to select other options.')); } }, completeAnnounceDelay); } }, [customCss.focused, customCss.selected, updateArrowIcon]); var finalizeEditing = (0, _react.useCallback)(function (orders) { if (mutableRef.current.initialSelected) { mutableRef.current.selectedItem.children[1].ariaLabel = "".concat(mutableRef.current.selectedItem.ariaLabel, " ").concat((0, _$L["default"])('Press the OK button to move or press the up button to select other options.')); } (0, _handle.forwardCustom)('onComplete', function () { return { orders: orders, hideIndex: mutableRef.current.hideIndex }; })(null, editable); reset(); }, [editable, reset]); var findItemNode = (0, _react.useCallback)(function (node) { for (var current = node; current !== scrollContentRef.current && current !== document; current = current.parentNode) { if (current.dataset.index) { return current; } } return null; }, [scrollContentRef]); var focusItem = (0, _react.useCallback)(function (target) { var itemNode = findItemNode(target); if (itemNode && !mutableRef.current.selectedItem) { var _mutableRef$current$f2, _mutableRef$current$f3; (_mutableRef$current$f2 = mutableRef.current.focusedItem) === null || _mutableRef$current$f2 === void 0 || _mutableRef$current$f2.classList.remove(customCss.focused); mutableRef.current.focusedItem = itemNode; (_mutableRef$current$f3 = mutableRef.current.focusedItem) === null || _mutableRef$current$f3 === void 0 || _mutableRef$current$f3.classList.add(customCss.focused); mutableRef.current.prevToIndex = Number(itemNode.style.order) - 1; } }, [customCss.focused, findItemNode]); var blurItem = (0, _react.useCallback)(function (target) { var itemNode = findItemNode(target); if (itemNode && !mutableRef.current.selectedItem) { var _mutableRef$current$f4; (_mutableRef$current$f4 = mutableRef.current.focusedItem) === null || _mutableRef$current$f4 === void 0 || _mutableRef$current$f4.classList.remove(customCss.focused); mutableRef.current.focusedItem = null; mutableRef.current.prevToIndex = null; } }, [customCss.focused, findItemNode]); var handleClickCapture = (0, _react.useCallback)(function (ev) { var _ev$target; if (((_ev$target = ev.target) === null || _ev$target === void 0 || (_ev$target = _ev$target.parentNode) === null || _ev$target === void 0 ? void 0 : _ev$target.parentNode.getAttribute('role')) === 'button') { return; } // Consume the event to prevent Item behavior if (mutableRef.current.selectedItem || mutableRef.current.needToPreventEvent) { ev.preventDefault(); ev.stopPropagation(); mutableRef.current.needToPreventEvent = false; } }, []); var handleMouseDown = (0, _react.useCallback)(function (ev) { var _ev$target2; if (((_ev$target2 = ev.target) === null || _ev$target2 === void 0 || (_ev$target2 = _ev$target2.parentNode) === null || _ev$target2 === void 0 ? void 0 : _ev$target2.parentNode.getAttribute('role')) === 'button') { return; } if (mutableRef.current.selectedItem) { // Finalize orders and forward `onComplete` event var orders = finalizeOrders(); finalizeEditing(orders); if (selectItemBy === 'press') { focusItem(ev.target); } mutableRef.current.needToPreventEvent = true; } else { var targetItemNode = findItemNode(ev.target); if (selectItemBy === 'press') { if (targetItemNode && targetItemNode.dataset.index) { // Start editing by adding selected transition to selected item mutableRef.current.targetItemNode = targetItemNode; startEditing(targetItemNode); } mutableRef.current.needToPreventEvent = true; } else { mutableRef.current.targetItemNode = targetItemNode; mutableRef.current.needToPreventEvent = false; } } }, [finalizeEditing, finalizeOrders, findItemNode, focusItem, selectItemBy, startEditing]); var handleHoldStart = (0, _react.useCallback)(function () { var targetItemNode = mutableRef.current.targetItemNode; if (targetItemNode && targetItemNode.dataset.index && selectItemBy === 'longPress') { // Start editing by adding selected transition to selected item startEditing(targetItemNode); } }, [selectItemBy, startEditing]); var readOutCurrentPosition = (0, _react.useCallback)(function (neighborItem) { var _mutableRef$current3 = mutableRef.current, lastInputDirection = _mutableRef$current3.lastInputDirection, lastInputType = _mutableRef$current3.lastInputType, selectedItemLabel = _mutableRef$current3.selectedItemLabel; if (lastInputType === 'key') { if (lastInputDirection === 'left') { announceRef.current.announce(new _IString["default"]((0, _$L["default"])('{selectedItem} moved to the left of {neighborItem}')).format({ selectedItem: selectedItemLabel, neighborItem: neighborItem }), true); } else { announceRef.current.announce(new _IString["default"]((0, _$L["default"])('{selectedItem} moved to the right of {neighborItem}')).format({ selectedItem: selectedItemLabel, neighborItem: neighborItem }), true); } } }, []); // Add rearranged items var addRearrangedItems = (0, _react.useCallback)(function (_ref) { var currentMoveDirection = _ref.currentMoveDirection, toIndex = _ref.toIndex; // Set the currentMoveDirection to css variable var rtl = scrollContainerHandle.current.rtl; wrapperRef.current.style.setProperty('--move-direction', currentMoveDirection * (rtl ? -1 : 1)); var _mutableRef$current4 = mutableRef.current, fromIndex = _mutableRef$current4.fromIndex, rearrangedItems = _mutableRef$current4.rearrangedItems, selectedItem = _mutableRef$current4.selectedItem; var getNextElement = function getNextElement(item) { return currentMoveDirection > 0 ? item.nextElementSibling : item.previousElementSibling; }; var sibling = getNextElement(selectedItem); var lastRearrangedItem; var start = currentMoveDirection > 0 ? toIndex : fromIndex; var end = currentMoveDirection > 0 ? fromIndex : toIndex; while (start > end && sibling) { var _sibling; (_sibling = sibling) === null || _sibling === void 0 || _sibling.classList.add(_EditableWrapperModule["default"].rearranged, _EditableWrapperModule["default"].rearrangedTransform); if (!rearrangedItems.includes(sibling)) { rearrangedItems.push(sibling); } lastRearrangedItem = sibling; sibling = getNextElement(sibling); start--; } if (lastRearrangedItem) { readOutCurrentPosition(lastRearrangedItem.ariaLabel || lastRearrangedItem.textContent); } mutableRef.current.moveDirection = currentMoveDirection; }, [readOutCurrentPosition, scrollContainerHandle]); var removeRearrangedItems = (0, _react.useCallback)(function (numToRemove) { var rearrangedItems = mutableRef.current.rearrangedItems; var toItem = null; if (rearrangedItems.length > 0) { for (var i = 0; i < numToRemove; i++) { var _toItem; toItem = rearrangedItems.pop(); (_toItem = toItem) === null || _toItem === void 0 || _toItem.classList.remove(_EditableWrapperModule["default"].rearrangedTransform); } } if (toItem) { readOutCurrentPosition(toItem.ariaLabel || toItem.textContent); } }, [readOutCurrentPosition]); // Move items var moveItems = (0, _react.useCallback)(function (toIndex) { var selectedItem = mutableRef.current.selectedItem; var rtl = scrollContainerHandle.current.rtl; if (selectedItem && !selectedItem.className.includes('hidden')) { // Bail out when index is out of scope if (toIndex < mutableRef.current.hideIndex && toIndex >= 0) { var _mutableRef$current5 = mutableRef.current, fromIndex = _mutableRef$current5.fromIndex, itemWidth = _mutableRef$current5.itemWidth, moveDirection = _mutableRef$current5.moveDirection, prevToIndex = _mutableRef$current5.prevToIndex, rearrangedItems = _mutableRef$current5.rearrangedItems; // Set the selected item's offset to css variable var offset = (toIndex - fromIndex) * itemWidth; wrapperRef.current.style.setProperty('--selected-item-offset', offset * (rtl ? -1 : 1) + 'px'); // If the current toIndex is new, if (toIndex !== prevToIndex) { // Determine the direction of move from the latest from index var currentMoveDirection = Math.sign(toIndex - prevToIndex); // If the direction is changed and there are rearranged items, we remove them first. if (moveDirection && currentMoveDirection !== moveDirection && rearrangedItems.length > 0) { var numToRemove = currentMoveDirection > 0 ? toIndex - prevToIndex : prevToIndex - toIndex; var needToAddItems = numToRemove > rearrangedItems.length; removeRearrangedItems(numToRemove); // When there's jump, meaning, numToRemove is bigger than 0, we need to add an item if (needToAddItems) { addRearrangedItems({ currentMoveDirection: currentMoveDirection, toIndex: toIndex }); } } else { addRearrangedItems({ currentMoveDirection: currentMoveDirection, toIndex: toIndex }); } mutableRef.current.prevToIndex = toIndex; } updateArrowIcon(toIndex); } } }, [addRearrangedItems, removeRearrangedItems, scrollContainerHandle, updateArrowIcon]); var moveItemsByKeyDown = (0, _react.useCallback)(function (ev) { var keyCode = ev.keyCode; var container = scrollContentRef.current; var _mutableRef$current6 = mutableRef.current, itemWidth = _mutableRef$current6.itemWidth, prevToIndex = _mutableRef$current6.prevToIndex; var rtl = scrollContainerHandle.current.rtl; var toIndex = !rtl ^ !(0, _keymap.is)('left', keyCode) ? prevToIndex - 1 : prevToIndex + 1; var scrollLeft = container.scrollLeft * (rtl ? -1 : 1); var itemLeft = toIndex * itemWidth - scrollLeft; var left; if (itemLeft > container.offsetLeft + container.clientWidth - itemWidth) { left = itemLeft - (container.clientWidth - itemWidth) + scrollLeft; } else if (itemLeft < 0) { left = scrollLeft + itemLeft; } if (left != null) { /* avoid null or undefined */ scrollContainerHandle.current.start({ targetX: left, targetY: 0 }); } mutableRef.current.lastInputDirection = (0, _keymap.is)('left', keyCode) ? 'left' : 'right'; moveItems(toIndex); if (toIndex <= 0) { announceRef.current.announce((0, _keymap.is)('left', keyCode) && !rtl && (0, _$L["default"])('LEFTMOST') || (0, _keymap.is)('right', keyCode) && rtl && (0, _$L["default"])('RIGHTMOST')); } else if (toIndex >= dataSize - 1) { announceRef.current.announce((0, _keymap.is)('right', keyCode) && !rtl && (0, _$L["default"])('RIGHTMOST') || (0, _keymap.is)('left', keyCode) && rtl && (0, _$L["default"])('LEFTMOST')); } }, [dataSize, moveItems, scrollContainerHandle, scrollContentRef]); // Remove an item var removeItem = (0, _react.useCallback)(function () { var _mutableRef$current7 = mutableRef.current, focusedItem = _mutableRef$current7.focusedItem, prevToIndex = _mutableRef$current7.prevToIndex, selectedItem = _mutableRef$current7.selectedItem; var targetItem = selectedItem || focusedItem; if (targetItem) { // rearrangedItems need for the case when removing item while moving selected item var rearrangedItems = mutableRef.current.rearrangedItems; var targetItemRect = targetItem && targetItem.getBoundingClientRect(); mutableRef.current.nextSpotlightRect = { x: targetItemRect.right, y: targetItemRect.top }; mutableRef.current.hideIndex -= 1; var orders = finalizeOrders(); orders.splice(prevToIndex, 1); rearrangedItems.forEach(function (item) { item.style.order -= 1; }); finalizeEditing(orders); } }, [finalizeEditing, finalizeOrders]); var hideItem = (0, _react.useCallback)(function () { var _mutableRef$current8 = mutableRef.current, focusedItem = _mutableRef$current8.focusedItem, selectedItem = _mutableRef$current8.selectedItem; var targetItem = selectedItem || focusedItem; if (targetItem) { // rearrangedItems need for the case when hiding item while moving selected item var rearrangedItems = mutableRef.current.rearrangedItems; var targetItemOrder = Number(targetItem.style.order); var targetItemRect = targetItem && targetItem.getBoundingClientRect(); mutableRef.current.nextSpotlightRect = { x: targetItemRect.right, y: targetItemRect.top }; mutableRef.current.hideIndex -= 1; var orders = finalizeOrders(); orders.splice(orders.indexOf(targetItemOrder), 1); orders.push(targetItemOrder); rearrangedItems.forEach(function (item) { item.style.order -= 1; }); targetItem.style.order = orders.length; finalizeEditing(orders); } }, [finalizeEditing, finalizeOrders]); var showItem = (0, _react.useCallback)(function () { var _mutableRef$current9 = mutableRef.current, focusedItem = _mutableRef$current9.focusedItem, selectedItem = _mutableRef$current9.selectedItem; var targetItem = selectedItem || focusedItem; if (targetItem) { var targetItemOrder = Number(targetItem.style.order); var targetItemRect = targetItem && targetItem.getBoundingClientRect(); mutableRef.current.nextSpotlightRect = { x: targetItemRect.right, y: targetItemRect.top }; var orders = Array.from({ length: dataSize }, function (_, i) { return i + 1; }); orders.splice(targetItemOrder - 1, 1); orders.splice(mutableRef.current.hideIndex, 0, targetItemOrder); mutableRef.current.hideIndex += 1; finalizeEditing(orders); } }, [dataSize, finalizeEditing]); var getNextIndexFromPosition = (0, _react.useCallback)(function (x, tolerance) { var _mutableRef$current10 = mutableRef.current, centeredOffset = _mutableRef$current10.centeredOffset, itemWidth = _mutableRef$current10.itemWidth, prevToIndex = _mutableRef$current10.prevToIndex; var rtl = scrollContainerHandle.current.rtl; var bodyWidth = document.body.getBoundingClientRect().width; // Determine toIndex with mouse client x position // Coordinate calculation in RTL locales is not supported in chrome below 85 var scrollContentOffset = scrollContentRef.current.scrollLeft * (rtl ? -1 : 1) - centeredOffset; var clientXFromContent = (rtl ? bodyWidth - x : x) + scrollContentOffset; var direction = itemWidth * (prevToIndex + 0.5) < clientXFromContent ? 1 : -1; // 1: To next index , -1: To prev index var moveTolerance = itemWidth * tolerance * direction; return Math.floor((clientXFromContent - moveTolerance) / itemWidth); }, [scrollContainerHandle, scrollContentRef]); var handlePointerDown = (0, _react.useCallback)(function (ev) { var selectedItem = mutableRef.current.selectedItem; if (selectedItem) { if (ev.target.hasPointerCapture(ev.pointerId)) { ev.target.releasePointerCapture(ev.pointerId); } } }, []); var handleMouseMove = (0, _react.useCallback)(function (ev) { var clientX = ev.clientX; mutableRef.current.lastMouseClientX = clientX; mutableRef.current.lastInputType = 'mouse'; if (mutableRef.current.selectedItem && Number(mutableRef.current.selectedItem.style.order) - 1 < mutableRef.current.hideIndex) { var toIndex = getNextIndexFromPosition(clientX, 0.33); moveItems(toIndex); } }, [getNextIndexFromPosition, moveItems]); var handleMouseLeave = (0, _react.useCallback)(function () { var _mutableRef$current11 = mutableRef.current, focusedItem = _mutableRef$current11.focusedItem, itemWidth = _mutableRef$current11.itemWidth, lastInputType = _mutableRef$current11.lastInputType, lastMouseClientX = _mutableRef$current11.lastMouseClientX, selectedItem = _mutableRef$current11.selectedItem; var rtl = scrollContainerHandle.current.rtl; var scrollContentNode = scrollContentRef.current; var scrollContentCenter = scrollContentNode.getBoundingClientRect().width / 2; if (selectedItem || focusedItem) { var orders = finalizeOrders(); finalizeEditing(orders); if (lastInputType === 'scroll') { var offset = itemWidth * (!rtl ^ !(lastMouseClientX > scrollContentCenter) ? 1 : -1); scrollContainerHandle.current.start({ targetX: scrollContentNode.scrollLeft + offset, targetY: 0 }); } } }, [finalizeEditing, finalizeOrders, scrollContainerHandle, scrollContentRef]); var completeEditingByKeyDown = (0, _react.useCallback)(function () { var _mutableRef$current12 = mutableRef.current, selectedItem = _mutableRef$current12.selectedItem, selectedItemLabel = _mutableRef$current12.selectedItemLabel; var focusTarget = selectedItem.children[1]; var orders = finalizeOrders(); finalizeEditing(orders); if (selectItemBy === 'press') { if ((0, _pointer.getPointerMode)()) { _spotlight["default"].setPointerMode(false); _spotlight["default"].focus(focusTarget); } focusItem(focusTarget); } setTimeout(function () { announceRef.current.announce(selectedItemLabel + (0, _$L["default"])('Movement completed'), true); setTimeout(function () { selectedItem.children[1].ariaLabel = "".concat(selectedItem.ariaLabel, " ").concat((0, _$L["default"])('Press the OK button to move or press the up button to select other options.')); }, completeAnnounceDelay); }, completeAnnounceDelay); }, [finalizeEditing, finalizeOrders, focusItem, selectItemBy]); var handleMoveItemsByKeyDown = (0, _react.useCallback)(function (ev, repeat) { var selectedItem = mutableRef.current.selectedItem; if (Number(selectedItem.style.order) - 1 < mutableRef.current.hideIndex) { if (repeat) { SpotlightAccelerator.processKey(ev, moveItemsByKeyDown); } else { SpotlightAccelerator.reset(); moveItemsByKeyDown(ev); } } ev.preventDefault(); ev.stopPropagation(); }, [moveItemsByKeyDown]); var handleFocusLeaveScrollContainer = (0, _react.useCallback)(function (ev, nextTarget) { if (nextTarget && !(0, _container.getContainersForNode)(nextTarget).includes(mutableRef.current.spotlightId)) { (0, _pointer.setPointerMode)(false); _spotlight["default"].focus(nextTarget); var orders = finalizeOrders(); finalizeEditing(orders); ev.preventDefault(); ev.stopPropagation(); } }, [finalizeEditing, finalizeOrders]); var handleKeyDownCapture = (0, _react.useCallback)(function (ev) { var keyCode = ev.keyCode, repeat = ev.repeat, target = ev.target; var _mutableRef$current13 = mutableRef.current, focusedItem = _mutableRef$current13.focusedItem, selectedItem = _mutableRef$current13.selectedItem; var targetItemNode = findItemNode(target); if ((0, _keymap.is)('enter', keyCode) && target.getAttribute('role') !== 'button') { if (!repeat) { if (selectedItem) { completeEditingByKeyDown(); mutableRef.current.needToPreventEvent = true; } else if (selectItemBy === 'press') { startEditing(targetItemNode); mutableRef.current.needToPreventEvent = true; } } else if (repeat && targetItemNode && !mutableRef.current.timer && selectItemBy === 'longPress') { mutableRef.current.timer = setTimeout(function () { startEditing(targetItemNode); }, holdDuration - 300); } } else if ((0, _keymap.is)('down', keyCode) && target.getAttribute('role') !== 'button' && !repeat && selectedItem) { completeEditingByKeyDown(); mutableRef.current.needToPreventEvent = true; } else if ((0, _keymap.is)('left', keyCode) || (0, _keymap.is)('right', keyCode)) { var nextTarget = (0, _target.getTargetByDirectionFromElement)((0, _spotlight.getDirection)(keyCode), target); if (selectedItem) { // If keyDown event target is item(=not button), move item. if (target.getAttribute('role') !== 'button') { handleMoveItemsByKeyDown(ev, repeat); // If keyDown event target is button and next spot target is item, move item and then spot selected item. } else if ((nextTarget === null || nextTarget === void 0 ? void 0 : nextTarget.getAttribute('role')) !== 'button') { handleMoveItemsByKeyDown(ev, repeat); (0, _pointer.setPointerMode)(false); _spotlight["default"].focus(selectedItem.children[1]); // If keyDown event target is button and next spot target is button, check whether focus leaves the scroll container. } else { // Check if focus leaves scroll container. handleFocusLeaveScrollContainer(ev, nextTarget); } } else if (nextTarget && !(0, _container.getContainersForNode)(nextTarget).includes(mutableRef.current.spotlightId) && !repeat) { // Check if focus leaves scroll container. handleFocusLeaveScrollContainer(ev, nextTarget); } } else if ((0, _keymap.is)('up', keyCode) || (0, _keymap.is)('down', keyCode)) { if (selectedItem || focusedItem) { var _nextTarget = (0, _target.getTargetByDirectionFromElement)((0, _spotlight.getDirection)(keyCode), target); // Check if focus leaves scroll container. handleFocusLeaveScrollContainer(ev, _nextTarget); } } }, [findItemNode, handleFocusLeaveScrollContainer, handleMoveItemsByKeyDown, selectItemBy, startEditing, completeEditingByKeyDown]); var handleKeyUpCapture = (0, _react.useCallback)(function (ev) { var keyCode = ev.keyCode, target = ev.target; var selectedItem = mutableRef.current.selectedItem; if ((0, _keymap.is)('cancel', keyCode)) { if (selectedItem) { completeEditingByKeyDown(); ev.stopPropagation(); // To prevent onCancel by CancelDecorator } } else if (target.getAttribute('role') === 'button') { return; } clearTimeout(mutableRef.current.timer); mutableRef.current.timer = null; if (mutableRef.current.needToPreventEvent || mutableRef.current.selectedItem) { ev.preventDefault(); mutableRef.current.needToPreventEvent = false; } }, [completeEditingByKeyDown]); var handleGlobalKeyDownCapture = (0, _react.useCallback)(function (ev) { var _mutableRef$current14 = mutableRef.current, focusedItem = _mutableRef$current14.focusedItem, selectedItem = _mutableRef$current14.selectedItem; mutableRef.current.lastInputType = 'key'; // If the pointer mode is `true` and the focused component is not contained in scrollContainerRef, // only `handleGlobalKeyDownCapture` is called instead of `handleKeyDownCapture` // Below is mainly for handling key pressed while pointer mode is `true`. if ((0, _pointer.getPointerMode)() && !scrollContainerRef.current.contains(_spotlight["default"].getCurrent()) && (selectedItem || focusedItem)) { var keyCode = ev.keyCode; var position = (0, _pointer.getLastPointerPosition)(); var direction = (0, _spotlight.getDirection)(keyCode); if (direction) { var nextTarget = (0, _target.getTargetByDirectionFromPosition)(direction, position, mutableRef.current.spotlightId); if (!scrollContainerRef.current.contains(nextTarget)) { // If the nextTarget is not contained in scrollContainerRef, complete editing var orders = finalizeOrders(); finalizeEditing(orders); } else if (((0, _keymap.is)('left', keyCode) || (0, _keymap.is)('right', keyCode)) && selectedItem) { // When an item is selected and press the `left` or `right` key, move the selectedItem in that direction moveItemsByKeyDown(ev); ev.preventDefault(); ev.stopPropagation(); } else if ((0, _keymap.is)('down', keyCode) && selectedItem) { // When an item is selected and press the `down` key, complete editing and focus the selectedItem completeEditingByKeyDown(); } else if ((0, _keymap.is)('up', keyCode) && nextTarget.getAttribute('role') !== 'button') { // When the nextTarget is the item and press the `up` key, focus the nextTarget to move focus successfully to the button above the item (0, _pointer.setPointerMode)(false); _spotlight["default"].focus(nextTarget); } } else if ((0, _keymap.is)('enter', keyCode)) { if (selectedItem) { // When an item is selected and press the `enter` key, complete editing and focus the selectedItem completeEditingByKeyDown(); } else { // When an item is focused and press the `enter` key, start editing startEditing(focusedItem); } } } }, [completeEditingByKeyDown, finalizeEditing, finalizeOrders, moveItemsByKeyDown, scrollContainerRef, startEditing]); var handleTouchMove = (0, _react.useCallback)(function (ev) { var _ev$target3; mutableRef.current.lastInputType = 'touch'; if (mutableRef.current.selectedItem) { // Prevent scrolling by dragging when item is selected ev.preventDefault(); } if (mutableRef.current.isDraggingItem && ((_ev$target3 = ev.target) === null || _ev$target3 === void 0 || (_ev$target3 = _ev$target3.parentNode) === null || _ev$target3 === void 0 ? void 0 : _ev$target3.parentNode.getAttribute('role')) !== 'button') { var clientX = ev.targetTouches[0].clientX; mutableRef.current.lastMouseClientX = clientX; scrollContainerRef.current.style.setProperty('--scroller-hover-to-scroll-by-touch', 'auto'); var toIndex = getNextIndexFromPosition(clientX, 0.33); if (toIndex !== mutableRef.current.prevToIndex) { moveItems(toIndex); } } }, [getNextIndexFromPosition, moveItems, scrollContainerRef]); var handleTouchEnd = (0, _react.useCallback)(function (ev) { var _ev$target4; var _mutableRef$current15 = mutableRef.current, itemWidth = _mutableRef$current15.itemWidth, lastInputType = _mutableRef$current15.lastInputType, lastMouseClientX = _mutableRef$current15.lastMouseClientX, selectedItem = _mutableRef$current15.selectedItem; var rtl = scrollContainerHandle.current.rtl; var scrollContentNode = scrollContentRef.current; var scrollContentCenter = scrollContentNode.getBoundingClientRect().width / 2; var clientX = ev.changedTouches[0].clientX; var targetItemIndex = getNextIndexFromPosition(clientX, 0); if (((_ev$target4 = ev.target) === null || _ev$target4 === void 0 || (_ev$target4 = _ev$target4.parentNode) === null || _ev$target4 === void 0 ? void 0 : _ev$target4.parentNode.getAttribute('role')) === 'button' && Number(selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.style.order) - 1 === targetItemIndex) { return; } if (selectedItem) { // Cancel mouse event to deselect a selected item when it is tapped ev.preventDefault(); // Finalize orders and forward `onComplete` event var orders = finalizeOrders(); finalizeEditing(orders); if (lastInputType === 'scroll' && mutableRef.current.isDragging) { var offset = itemWidth * (!rtl ^ !(lastMouseClientX > scrollContentCenter) ? 1 : -1); scrollContainerHandle.current.start({ targetX: scrollContentNode.scrollLeft + offset, targetY: 0 }); } } else if (!mutableRef.current.isDragging) { // Cancel mouse event to select a item when it is tapped ev.preventDefault(); var targetItemNode = findItemNode(ev.target); if (selectItemBy === 'press') { if (targetItemNode && targetItemNode.dataset.index) { mutableRef.current.targetItemNode = targetItemNode; startEditing(targetItemNode); } } } mutableRef.current.isDraggingItem = false; mutableRef.current.isDragging = false; scrollContainerRef.current.style.setProperty('--scroller-hover-to-scroll-by-touch', 'none'); }, [getNextIndexFromPosition, finalizeEditing, finalizeOrders, findItemNode, scrollContainerHandle, scrollContainerRef, scrollContentRef, selectItemBy, startEditing]); var handleDragStart = (0, _react.useCallback)(function (ev) { var selectedItem = mutableRef.current.selectedItem; // Index of dragged item var dragTagetItemIndex = getNextIndexFromPosition(ev.x, 0); mutableRef.current.isDragging = true; if (selectedItem && Number(selectedItem.style.order) - 1 === dragTagetItemIndex) { mutableRef.current.isDraggingItem = true; } }, [getNextIndexFromPosition]); (0, _react.useLayoutEffect)(function () { var available = typeof document === 'object'; if (available) { document.addEventListener('keydown', handleGlobalKeyDownCapture, { capture: true }); } return function () { if (available) { document.removeEventListener('keydown', handleGlobalKeyDownCapture, { capture: true }); } }; }, [handleGlobalKeyDownCapture]); (0, _react.useEffect)(function () { if (mutableRef.current.nextSpotlightRect !== null) { _spotlight["default"].focusNextFromPoint('down', mutableRef.current.nextSpotlightRect); mutableRef.current.nextSpotlightRect = null; } }); (0, _react.useEffect)(function () { var _wrapperRef$current; // Calculate the item width once var rtl = scrollContainerHandle.current.rtl; var container = scrollContentRef.current; var item = (_wrapperRef$current = wrapperRef.current) === null || _wrapperRef$current === void 0 ? void 0 : _wrapperRef$current.children[0]; if (item && typeof window !== 'undefined') { var _wrapperRef$current2; var bodyWidth = document.body.getBoundingClientRect().width; var neighbor = item.nextElementSibling || item.previousElementSibling; mutableRef.current.itemWidth = Math.abs(item.offsetLeft - (neighbor === null || neighbor === void 0 ? void 0 : neighbor.offsetLeft)); mutableRef.current.centeredOffset = rtl ? bodyWidth - (item.getBoundingClientRect().right + container.scrollLeft) : item.getBoundingClientRect().left + container.scrollLeft; (_wrapperRef$current2 = wrapperRef.current) === null || _wrapperRef$current2 === void 0 || _wrapperRef$current2.style.setProperty('--item-width', mutableRef.current.itemWidth + 'px'); } }, [centered, dataSize, scrollContainerHandle, scrollContentRef]); (0, _react.useEffect)(function () { mutableRef.current.spotlightId = scrollContainerRef.current && scrollContainerRef.current.dataset.spotlightId; }, [scrollContainerRef]); (0, _react.useEffect)(function () { var scrollContainer = scrollContainerRef.current; if (scrollContainer) { scrollContainer.addEventListener('mouseleave', handleMouseLeave); scrollContainer.addEventListener('touchmove', handleTouchMove); } return function () { if (scrollContainer) { scrollContainer.removeEventListener('mouseleave', handleMouseLeave); scrollContainer.removeEventListener('touchmove', handleTouchMove); } }; }, [handleMouseLeave, handleTouchMove, scrollContainerRef]); (0, _react.useLayoutEffect)(function () { if (removeItemFuncRef) { removeItemFuncRef.current = removeItem; } }, [removeItem, removeItemFuncRef]); (0, _react.useLayoutEffect)(function () { if (hideItemFuncRef) { hideItemFuncRef.current = hideItem; } }, [hideItem, hideItemFuncRef]); (0, _react.useLayoutEffect)(function () { if (showItemFuncRef) { showItemFuncRef.current = showItem; } }, [showItem, showItemFuncRef]); (0, _react.useLayoutEffect)(function () { if (focusItemFuncRef) { focusItemFuncRef.current = focusItem; } }, [focusItem, focusItemFuncRef]); (0, _react.useLayoutEffect)(function () { if (blurItemFuncRef) { blurItemFuncRef.current = blurItem; } }, [blurItem, blurItemFuncRef]); (0, _react.useEffect)(function () { // addEventListener to moveItems while scrolled var scrollContentNode = scrollContentRef.current; var handleMoveItemsByScroll = function handleMoveItemsByScroll() { var bodyWidth = document.body.getBoundingClientRect().width; var _mutableRef$current16 = mutableRef.current, lastMouseClientX = _mutableRef$current16.lastMouseClientX, selectedItem = _mutableRef$current16.selectedItem; var _scrollContainerHandl = scrollContainerHandle.current, isHoveringToScroll = _scrollContainerHandl.isHoveringToScroll, rtl = _scrollContainerHandl.rtl; if (selectedItem && mutableRef.current.lastInputType !== 'key' && Number(selectedItem.style.order) - 1 < mutableRef.current.hideIndex) { mutableRef.current.lastInputType = 'scroll'; if (isHoveringToScroll) { var toIndex = getNextIndexFromPosition(lastMouseClientX, 0); moveItems(!rtl ^ !(lastMouseClientX > bodyWidth / 2) ? toIndex + 1 : toIndex - 1); } else { moveItems(getNextIndexFromPosition(lastMouseClientX, 0.33)); } } }; setTimeout(function () { scrollContentNode.addEventListener('scroll', handleMoveItemsByScroll); }, 400); // Wait for finishing scroll animation when initial selected item is given. return function () { scrollContentNode.removeEventListener('scroll', handleMoveItemsByScroll); }; }, [getNextIndexFromPosition, moveItems, scrollContainerHandle, scrollContentRef]); (0, _react.useEffect)(function () { if (mutableRef.current.initialSelected) { var _scrollContainerHandl2; (_scrollContainerHandl2 = scrollContainerHandle.current) === null || _scrollContainerHandl2 === void 0 || _scrollContainerHandl2.scrollTo({ animate: false, position: { x: mutableRef.current.initialSelected.scrollLeft } }); } }, [scrollContainerHandle]); (0, _react.useLayoutEffect)(function () { var _initialSelected, _initialSelected2; var iconItemList = Array.from(wrapperRef.current.children); var initialSelected = mutableRef.current.initialSelected; if (initialSelected && !(((_initialSelected = initialSelected) === null || _initialSelected === void 0 ? void 0 : _initialSelected.itemIndex) > 0)) { // filter nullish values initialSelected = mutableRef.current.initialSelected = null; } if ((_initialSelected2 = initialSelected) !== null && _initialSelected2 !== void 0 && _initialSelected2.itemIndex) { var _initialSelected3; var initialSelectedItem = wrapperRef.current.children[((_initialSelected3 = initialSelected) === null || _initialSelected3 === void 0 ? void 0 : _initialSelected3.itemIndex) - 1]; if (initialSelectedItem !== null && initialSelectedItem !== void 0 && initialSelectedItem.dataset.index) { mutableRef.current.focusedItem = initialSelectedItem; mutableRef.current.lastMouseClientX = (0, _pointer.getLastPointerPosition)().x; startEditing(initialSelectedItem); (0, _pointer.setPointerMode)(false); _spotlight["default"].focus(initialSelectedItem.children[1]); } } iconItemList.forEach(function (iconItemWrapper, index) { if (iconItemWrapper !== null && iconItemWrapper !== void 0 && iconItemWrapper.children[1]) { if (initialSelected && initialSelected.itemIndex - 1 === index) { iconItemWrapper.children[1].ariaLabel += " ".concat((0, _$L["default"])('Press the left/right button to move or press the up button to select other options.')); } else { iconItemWrapper.children[1].ariaLabel += " ".concat((0, _$L["default"])('Press the OK button to move or press the up button to select other options.')); } } }); }, []); // eslint-disable-line react-hooks/exhaustive-deps return /*#__PURE__*/(0, _jsxRuntime.jsxs)(TouchableDiv, { holdConfig: holdConfig, className: (0, _classnames["default"])(mergedCss.wrapper, _def