538 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			538 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { isShadowRoot, isHTMLElement } from '@floating-ui/utils/dom';
 | |
| import * as React from 'react';
 | |
| import { useLayoutEffect } from 'react';
 | |
| import { floor } from '@floating-ui/utils';
 | |
| import { tabbable } from 'tabbable';
 | |
| 
 | |
| // Avoid Chrome DevTools blue warning.
 | |
| function getPlatform() {
 | |
|   const uaData = navigator.userAgentData;
 | |
|   if (uaData != null && uaData.platform) {
 | |
|     return uaData.platform;
 | |
|   }
 | |
|   return navigator.platform;
 | |
| }
 | |
| function getUserAgent() {
 | |
|   const uaData = navigator.userAgentData;
 | |
|   if (uaData && Array.isArray(uaData.brands)) {
 | |
|     return uaData.brands.map(_ref => {
 | |
|       let {
 | |
|         brand,
 | |
|         version
 | |
|       } = _ref;
 | |
|       return brand + "/" + version;
 | |
|     }).join(' ');
 | |
|   }
 | |
|   return navigator.userAgent;
 | |
| }
 | |
| function isSafari() {
 | |
|   // Chrome DevTools does not complain about navigator.vendor
 | |
|   return /apple/i.test(navigator.vendor);
 | |
| }
 | |
| function isAndroid() {
 | |
|   const re = /android/i;
 | |
|   return re.test(getPlatform()) || re.test(getUserAgent());
 | |
| }
 | |
| function isMac() {
 | |
|   return getPlatform().toLowerCase().startsWith('mac') && !navigator.maxTouchPoints;
 | |
| }
 | |
| function isJSDOM() {
 | |
|   return getUserAgent().includes('jsdom/');
 | |
| }
 | |
| 
 | |
| const FOCUSABLE_ATTRIBUTE = 'data-floating-ui-focusable';
 | |
| const TYPEABLE_SELECTOR = "input:not([type='hidden']):not([disabled])," + "[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";
 | |
| const ARROW_LEFT = 'ArrowLeft';
 | |
| const ARROW_RIGHT = 'ArrowRight';
 | |
| const ARROW_UP = 'ArrowUp';
 | |
| const ARROW_DOWN = 'ArrowDown';
 | |
| 
 | |
| function activeElement(doc) {
 | |
|   let activeElement = doc.activeElement;
 | |
|   while (((_activeElement = activeElement) == null || (_activeElement = _activeElement.shadowRoot) == null ? void 0 : _activeElement.activeElement) != null) {
 | |
|     var _activeElement;
 | |
|     activeElement = activeElement.shadowRoot.activeElement;
 | |
|   }
 | |
|   return activeElement;
 | |
| }
 | |
| function contains(parent, child) {
 | |
|   if (!parent || !child) {
 | |
|     return false;
 | |
|   }
 | |
|   const rootNode = child.getRootNode == null ? void 0 : child.getRootNode();
 | |
| 
 | |
|   // First, attempt with faster native method
 | |
|   if (parent.contains(child)) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   // then fallback to custom implementation with Shadow DOM support
 | |
|   if (rootNode && isShadowRoot(rootNode)) {
 | |
|     let next = child;
 | |
|     while (next) {
 | |
|       if (parent === next) {
 | |
|         return true;
 | |
|       }
 | |
|       // @ts-ignore
 | |
|       next = next.parentNode || next.host;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Give up, the result is false
 | |
|   return false;
 | |
| }
 | |
| function getTarget(event) {
 | |
|   if ('composedPath' in event) {
 | |
|     return event.composedPath()[0];
 | |
|   }
 | |
| 
 | |
|   // TS thinks `event` is of type never as it assumes all browsers support
 | |
|   // `composedPath()`, but browsers without shadow DOM don't.
 | |
|   return event.target;
 | |
| }
 | |
| function isEventTargetWithin(event, node) {
 | |
|   if (node == null) {
 | |
|     return false;
 | |
|   }
 | |
|   if ('composedPath' in event) {
 | |
|     return event.composedPath().includes(node);
 | |
|   }
 | |
| 
 | |
|   // TS thinks `event` is of type never as it assumes all browsers support composedPath, but browsers without shadow dom don't
 | |
|   const e = event;
 | |
|   return e.target != null && node.contains(e.target);
 | |
| }
 | |
| function isRootElement(element) {
 | |
|   return element.matches('html,body');
 | |
| }
 | |
| function getDocument(node) {
 | |
|   return (node == null ? void 0 : node.ownerDocument) || document;
 | |
| }
 | |
| function isTypeableElement(element) {
 | |
|   return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);
 | |
| }
 | |
| function isTypeableCombobox(element) {
 | |
|   if (!element) return false;
 | |
|   return element.getAttribute('role') === 'combobox' && isTypeableElement(element);
 | |
| }
 | |
| function matchesFocusVisible(element) {
 | |
|   // We don't want to block focus from working with `visibleOnly`
 | |
|   // (JSDOM doesn't match `:focus-visible` when the element has `:focus`)
 | |
|   if (!element || isJSDOM()) return true;
 | |
|   try {
 | |
|     return element.matches(':focus-visible');
 | |
|   } catch (_e) {
 | |
|     return true;
 | |
|   }
 | |
| }
 | |
| function getFloatingFocusElement(floatingElement) {
 | |
|   if (!floatingElement) {
 | |
|     return null;
 | |
|   }
 | |
|   // Try to find the element that has `{...getFloatingProps()}` spread on it.
 | |
|   // This indicates the floating element is acting as a positioning wrapper, and
 | |
|   // so focus should be managed on the child element with the event handlers and
 | |
|   // aria props.
 | |
|   return floatingElement.hasAttribute(FOCUSABLE_ATTRIBUTE) ? floatingElement : floatingElement.querySelector("[" + FOCUSABLE_ATTRIBUTE + "]") || floatingElement;
 | |
| }
 | |
| 
 | |
| function getNodeChildren(nodes, id, onlyOpenChildren) {
 | |
|   if (onlyOpenChildren === void 0) {
 | |
|     onlyOpenChildren = true;
 | |
|   }
 | |
|   const directChildren = nodes.filter(node => {
 | |
|     var _node$context;
 | |
|     return node.parentId === id && (!onlyOpenChildren || ((_node$context = node.context) == null ? void 0 : _node$context.open));
 | |
|   });
 | |
|   return directChildren.flatMap(child => [child, ...getNodeChildren(nodes, child.id, onlyOpenChildren)]);
 | |
| }
 | |
| function getDeepestNode(nodes, id) {
 | |
|   let deepestNodeId;
 | |
|   let maxDepth = -1;
 | |
|   function findDeepest(nodeId, depth) {
 | |
|     if (depth > maxDepth) {
 | |
|       deepestNodeId = nodeId;
 | |
|       maxDepth = depth;
 | |
|     }
 | |
|     const children = getNodeChildren(nodes, nodeId);
 | |
|     children.forEach(child => {
 | |
|       findDeepest(child.id, depth + 1);
 | |
|     });
 | |
|   }
 | |
|   findDeepest(id, 0);
 | |
|   return nodes.find(node => node.id === deepestNodeId);
 | |
| }
 | |
| function getNodeAncestors(nodes, id) {
 | |
|   var _nodes$find;
 | |
|   let allAncestors = [];
 | |
|   let currentParentId = (_nodes$find = nodes.find(node => node.id === id)) == null ? void 0 : _nodes$find.parentId;
 | |
|   while (currentParentId) {
 | |
|     const currentNode = nodes.find(node => node.id === currentParentId);
 | |
|     currentParentId = currentNode == null ? void 0 : currentNode.parentId;
 | |
|     if (currentNode) {
 | |
|       allAncestors = allAncestors.concat(currentNode);
 | |
|     }
 | |
|   }
 | |
|   return allAncestors;
 | |
| }
 | |
| 
 | |
| function stopEvent(event) {
 | |
|   event.preventDefault();
 | |
|   event.stopPropagation();
 | |
| }
 | |
| function isReactEvent(event) {
 | |
|   return 'nativeEvent' in event;
 | |
| }
 | |
| 
 | |
| // License: https://github.com/adobe/react-spectrum/blob/b35d5c02fe900badccd0cf1a8f23bb593419f238/packages/@react-aria/utils/src/isVirtualEvent.ts
 | |
| function isVirtualClick(event) {
 | |
|   // FIXME: Firefox is now emitting a deprecation warning for `mozInputSource`.
 | |
|   // Try to find a workaround for this. `react-aria` source still has the check.
 | |
|   if (event.mozInputSource === 0 && event.isTrusted) {
 | |
|     return true;
 | |
|   }
 | |
|   if (isAndroid() && event.pointerType) {
 | |
|     return event.type === 'click' && event.buttons === 1;
 | |
|   }
 | |
|   return event.detail === 0 && !event.pointerType;
 | |
| }
 | |
| function isVirtualPointerEvent(event) {
 | |
|   if (isJSDOM()) return false;
 | |
|   return !isAndroid() && event.width === 0 && event.height === 0 || isAndroid() && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||
 | |
|   // iOS VoiceOver returns 0.333• for width/height.
 | |
|   event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';
 | |
| }
 | |
| function isMouseLikePointerType(pointerType, strict) {
 | |
|   // On some Linux machines with Chromium, mouse inputs return a `pointerType`
 | |
|   // of "pen": https://github.com/floating-ui/floating-ui/issues/2015
 | |
|   const values = ['mouse', 'pen'];
 | |
|   if (!strict) {
 | |
|     values.push('', undefined);
 | |
|   }
 | |
|   return values.includes(pointerType);
 | |
| }
 | |
| 
 | |
| var isClient = typeof document !== 'undefined';
 | |
| 
 | |
| var noop = function noop() {};
 | |
| var index = isClient ? useLayoutEffect : noop;
 | |
| 
 | |
| // https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
 | |
| const SafeReact = {
 | |
|   ...React
 | |
| };
 | |
| 
 | |
| function useLatestRef(value) {
 | |
|   const ref = React.useRef(value);
 | |
|   index(() => {
 | |
|     ref.current = value;
 | |
|   });
 | |
|   return ref;
 | |
| }
 | |
| const useInsertionEffect = SafeReact.useInsertionEffect;
 | |
| const useSafeInsertionEffect = useInsertionEffect || (fn => fn());
 | |
| function useEffectEvent(callback) {
 | |
|   const ref = React.useRef(() => {
 | |
|     if (process.env.NODE_ENV !== "production") {
 | |
|       throw new Error('Cannot call an event handler while rendering.');
 | |
|     }
 | |
|   });
 | |
|   useSafeInsertionEffect(() => {
 | |
|     ref.current = callback;
 | |
|   });
 | |
|   return React.useCallback(function () {
 | |
|     for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
 | |
|       args[_key] = arguments[_key];
 | |
|     }
 | |
|     return ref.current == null ? void 0 : ref.current(...args);
 | |
|   }, []);
 | |
| }
 | |
| 
 | |
| function isDifferentGridRow(index, cols, prevRow) {
 | |
|   return Math.floor(index / cols) !== prevRow;
 | |
| }
 | |
| function isIndexOutOfListBounds(listRef, index) {
 | |
|   return index < 0 || index >= listRef.current.length;
 | |
| }
 | |
| function getMinListIndex(listRef, disabledIndices) {
 | |
|   return findNonDisabledListIndex(listRef, {
 | |
|     disabledIndices
 | |
|   });
 | |
| }
 | |
| function getMaxListIndex(listRef, disabledIndices) {
 | |
|   return findNonDisabledListIndex(listRef, {
 | |
|     decrement: true,
 | |
|     startingIndex: listRef.current.length,
 | |
|     disabledIndices
 | |
|   });
 | |
| }
 | |
| function findNonDisabledListIndex(listRef, _temp) {
 | |
|   let {
 | |
|     startingIndex = -1,
 | |
|     decrement = false,
 | |
|     disabledIndices,
 | |
|     amount = 1
 | |
|   } = _temp === void 0 ? {} : _temp;
 | |
|   let index = startingIndex;
 | |
|   do {
 | |
|     index += decrement ? -amount : amount;
 | |
|   } while (index >= 0 && index <= listRef.current.length - 1 && isListIndexDisabled(listRef, index, disabledIndices));
 | |
|   return index;
 | |
| }
 | |
| function getGridNavigatedIndex(listRef, _ref) {
 | |
|   let {
 | |
|     event,
 | |
|     orientation,
 | |
|     loop,
 | |
|     rtl,
 | |
|     cols,
 | |
|     disabledIndices,
 | |
|     minIndex,
 | |
|     maxIndex,
 | |
|     prevIndex,
 | |
|     stopEvent: stop = false
 | |
|   } = _ref;
 | |
|   let nextIndex = prevIndex;
 | |
|   if (event.key === ARROW_UP) {
 | |
|     stop && stopEvent(event);
 | |
|     if (prevIndex === -1) {
 | |
|       nextIndex = maxIndex;
 | |
|     } else {
 | |
|       nextIndex = findNonDisabledListIndex(listRef, {
 | |
|         startingIndex: nextIndex,
 | |
|         amount: cols,
 | |
|         decrement: true,
 | |
|         disabledIndices
 | |
|       });
 | |
|       if (loop && (prevIndex - cols < minIndex || nextIndex < 0)) {
 | |
|         const col = prevIndex % cols;
 | |
|         const maxCol = maxIndex % cols;
 | |
|         const offset = maxIndex - (maxCol - col);
 | |
|         if (maxCol === col) {
 | |
|           nextIndex = maxIndex;
 | |
|         } else {
 | |
|           nextIndex = maxCol > col ? offset : offset - cols;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (isIndexOutOfListBounds(listRef, nextIndex)) {
 | |
|       nextIndex = prevIndex;
 | |
|     }
 | |
|   }
 | |
|   if (event.key === ARROW_DOWN) {
 | |
|     stop && stopEvent(event);
 | |
|     if (prevIndex === -1) {
 | |
|       nextIndex = minIndex;
 | |
|     } else {
 | |
|       nextIndex = findNonDisabledListIndex(listRef, {
 | |
|         startingIndex: prevIndex,
 | |
|         amount: cols,
 | |
|         disabledIndices
 | |
|       });
 | |
|       if (loop && prevIndex + cols > maxIndex) {
 | |
|         nextIndex = findNonDisabledListIndex(listRef, {
 | |
|           startingIndex: prevIndex % cols - cols,
 | |
|           amount: cols,
 | |
|           disabledIndices
 | |
|         });
 | |
|       }
 | |
|     }
 | |
|     if (isIndexOutOfListBounds(listRef, nextIndex)) {
 | |
|       nextIndex = prevIndex;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Remains on the same row/column.
 | |
|   if (orientation === 'both') {
 | |
|     const prevRow = floor(prevIndex / cols);
 | |
|     if (event.key === (rtl ? ARROW_LEFT : ARROW_RIGHT)) {
 | |
|       stop && stopEvent(event);
 | |
|       if (prevIndex % cols !== cols - 1) {
 | |
|         nextIndex = findNonDisabledListIndex(listRef, {
 | |
|           startingIndex: prevIndex,
 | |
|           disabledIndices
 | |
|         });
 | |
|         if (loop && isDifferentGridRow(nextIndex, cols, prevRow)) {
 | |
|           nextIndex = findNonDisabledListIndex(listRef, {
 | |
|             startingIndex: prevIndex - prevIndex % cols - 1,
 | |
|             disabledIndices
 | |
|           });
 | |
|         }
 | |
|       } else if (loop) {
 | |
|         nextIndex = findNonDisabledListIndex(listRef, {
 | |
|           startingIndex: prevIndex - prevIndex % cols - 1,
 | |
|           disabledIndices
 | |
|         });
 | |
|       }
 | |
|       if (isDifferentGridRow(nextIndex, cols, prevRow)) {
 | |
|         nextIndex = prevIndex;
 | |
|       }
 | |
|     }
 | |
|     if (event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT)) {
 | |
|       stop && stopEvent(event);
 | |
|       if (prevIndex % cols !== 0) {
 | |
|         nextIndex = findNonDisabledListIndex(listRef, {
 | |
|           startingIndex: prevIndex,
 | |
|           decrement: true,
 | |
|           disabledIndices
 | |
|         });
 | |
|         if (loop && isDifferentGridRow(nextIndex, cols, prevRow)) {
 | |
|           nextIndex = findNonDisabledListIndex(listRef, {
 | |
|             startingIndex: prevIndex + (cols - prevIndex % cols),
 | |
|             decrement: true,
 | |
|             disabledIndices
 | |
|           });
 | |
|         }
 | |
|       } else if (loop) {
 | |
|         nextIndex = findNonDisabledListIndex(listRef, {
 | |
|           startingIndex: prevIndex + (cols - prevIndex % cols),
 | |
|           decrement: true,
 | |
|           disabledIndices
 | |
|         });
 | |
|       }
 | |
|       if (isDifferentGridRow(nextIndex, cols, prevRow)) {
 | |
|         nextIndex = prevIndex;
 | |
|       }
 | |
|     }
 | |
|     const lastRow = floor(maxIndex / cols) === prevRow;
 | |
|     if (isIndexOutOfListBounds(listRef, nextIndex)) {
 | |
|       if (loop && lastRow) {
 | |
|         nextIndex = event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT) ? maxIndex : findNonDisabledListIndex(listRef, {
 | |
|           startingIndex: prevIndex - prevIndex % cols - 1,
 | |
|           disabledIndices
 | |
|         });
 | |
|       } else {
 | |
|         nextIndex = prevIndex;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return nextIndex;
 | |
| }
 | |
| 
 | |
| /** For each cell index, gets the item index that occupies that cell */
 | |
| function createGridCellMap(sizes, cols, dense) {
 | |
|   const cellMap = [];
 | |
|   let startIndex = 0;
 | |
|   sizes.forEach((_ref2, index) => {
 | |
|     let {
 | |
|       width,
 | |
|       height
 | |
|     } = _ref2;
 | |
|     if (width > cols) {
 | |
|       if (process.env.NODE_ENV !== "production") {
 | |
|         throw new Error("[Floating UI]: Invalid grid - item width at index " + index + " is greater than grid columns");
 | |
|       }
 | |
|     }
 | |
|     let itemPlaced = false;
 | |
|     if (dense) {
 | |
|       startIndex = 0;
 | |
|     }
 | |
|     while (!itemPlaced) {
 | |
|       const targetCells = [];
 | |
|       for (let i = 0; i < width; i++) {
 | |
|         for (let j = 0; j < height; j++) {
 | |
|           targetCells.push(startIndex + i + j * cols);
 | |
|         }
 | |
|       }
 | |
|       if (startIndex % cols + width <= cols && targetCells.every(cell => cellMap[cell] == null)) {
 | |
|         targetCells.forEach(cell => {
 | |
|           cellMap[cell] = index;
 | |
|         });
 | |
|         itemPlaced = true;
 | |
|       } else {
 | |
|         startIndex++;
 | |
|       }
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   // convert into a non-sparse array
 | |
|   return [...cellMap];
 | |
| }
 | |
| 
 | |
| /** Gets cell index of an item's corner or -1 when index is -1. */
 | |
| function getGridCellIndexOfCorner(index, sizes, cellMap, cols, corner) {
 | |
|   if (index === -1) return -1;
 | |
|   const firstCellIndex = cellMap.indexOf(index);
 | |
|   const sizeItem = sizes[index];
 | |
|   switch (corner) {
 | |
|     case 'tl':
 | |
|       return firstCellIndex;
 | |
|     case 'tr':
 | |
|       if (!sizeItem) {
 | |
|         return firstCellIndex;
 | |
|       }
 | |
|       return firstCellIndex + sizeItem.width - 1;
 | |
|     case 'bl':
 | |
|       if (!sizeItem) {
 | |
|         return firstCellIndex;
 | |
|       }
 | |
|       return firstCellIndex + (sizeItem.height - 1) * cols;
 | |
|     case 'br':
 | |
|       return cellMap.lastIndexOf(index);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /** Gets all cell indices that correspond to the specified indices */
 | |
| function getGridCellIndices(indices, cellMap) {
 | |
|   return cellMap.flatMap((index, cellIndex) => indices.includes(index) ? [cellIndex] : []);
 | |
| }
 | |
| function isListIndexDisabled(listRef, index, disabledIndices) {
 | |
|   if (typeof disabledIndices === 'function') {
 | |
|     return disabledIndices(index);
 | |
|   } else if (disabledIndices) {
 | |
|     return disabledIndices.includes(index);
 | |
|   }
 | |
|   const element = listRef.current[index];
 | |
|   return element == null || element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';
 | |
| }
 | |
| 
 | |
| const getTabbableOptions = () => ({
 | |
|   getShadowRoot: true,
 | |
|   displayCheck:
 | |
|   // JSDOM does not support the `tabbable` library. To solve this we can
 | |
|   // check if `ResizeObserver` is a real function (not polyfilled), which
 | |
|   // determines if the current environment is JSDOM-like.
 | |
|   typeof ResizeObserver === 'function' && ResizeObserver.toString().includes('[native code]') ? 'full' : 'none'
 | |
| });
 | |
| function getTabbableIn(container, dir) {
 | |
|   const list = tabbable(container, getTabbableOptions());
 | |
|   const len = list.length;
 | |
|   if (len === 0) return;
 | |
|   const active = activeElement(getDocument(container));
 | |
|   const index = list.indexOf(active);
 | |
|   const nextIndex = index === -1 ? dir === 1 ? 0 : len - 1 : index + dir;
 | |
|   return list[nextIndex];
 | |
| }
 | |
| function getNextTabbable(referenceElement) {
 | |
|   return getTabbableIn(getDocument(referenceElement).body, 1) || referenceElement;
 | |
| }
 | |
| function getPreviousTabbable(referenceElement) {
 | |
|   return getTabbableIn(getDocument(referenceElement).body, -1) || referenceElement;
 | |
| }
 | |
| function isOutsideEvent(event, container) {
 | |
|   const containerElement = container || event.currentTarget;
 | |
|   const relatedTarget = event.relatedTarget;
 | |
|   return !relatedTarget || !contains(containerElement, relatedTarget);
 | |
| }
 | |
| function disableFocusInside(container) {
 | |
|   const tabbableElements = tabbable(container, getTabbableOptions());
 | |
|   tabbableElements.forEach(element => {
 | |
|     element.dataset.tabindex = element.getAttribute('tabindex') || '';
 | |
|     element.setAttribute('tabindex', '-1');
 | |
|   });
 | |
| }
 | |
| function enableFocusInside(container) {
 | |
|   const elements = container.querySelectorAll('[data-tabindex]');
 | |
|   elements.forEach(element => {
 | |
|     const tabindex = element.dataset.tabindex;
 | |
|     delete element.dataset.tabindex;
 | |
|     if (tabindex) {
 | |
|       element.setAttribute('tabindex', tabindex);
 | |
|     } else {
 | |
|       element.removeAttribute('tabindex');
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| export { activeElement, contains, createGridCellMap, disableFocusInside, enableFocusInside, findNonDisabledListIndex, getDeepestNode, getDocument, getFloatingFocusElement, getGridCellIndexOfCorner, getGridCellIndices, getGridNavigatedIndex, getMaxListIndex, getMinListIndex, getNextTabbable, getNodeAncestors, getNodeChildren, getPlatform, getPreviousTabbable, getTabbableOptions, getTarget, getUserAgent, isAndroid, isDifferentGridRow, isEventTargetWithin, isIndexOutOfListBounds, isJSDOM, isListIndexDisabled, isMac, isMouseLikePointerType, isOutsideEvent, isReactEvent, isRootElement, isSafari, isTypeableCombobox, isTypeableElement, isVirtualClick, isVirtualPointerEvent, matchesFocusVisible, stopEvent, useEffectEvent, useLatestRef, index as useModernLayoutEffect };
 | 
