(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('react-dom'), require('@floating-ui/react-dom')) : typeof define === 'function' && define.amd ? define(['exports', 'react', 'react-dom', '@floating-ui/react-dom'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.FloatingUIReact = {}, global.React, global.ReactDOM, global.FloatingUIReactDOM)); })(this, (function (exports, React, ReactDOM, reactDom) { 'use strict'; function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React); var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM); /** * Merges an array of refs into a single memoized callback ref or `null`. * @see https://floating-ui.com/docs/react-utils#usemergerefs */ function useMergeRefs(refs) { return React__namespace.useMemo(() => { if (refs.every(ref => ref == null)) { return null; } return value => { refs.forEach(ref => { if (typeof ref === 'function') { ref(value); } else if (ref != null) { ref.current = value; } }); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, refs); } // https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379 const SafeReact = { ...React__namespace }; const useInsertionEffect = SafeReact.useInsertionEffect; const useSafeInsertionEffect = useInsertionEffect || (fn => fn()); function useEffectEvent(callback) { const ref = React__namespace.useRef(() => { { throw new Error('Cannot call an event handler while rendering.'); } }); useSafeInsertionEffect(() => { ref.current = callback; }); return React__namespace.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 hasWindow() { return typeof window !== 'undefined'; } function getNodeName(node) { if (isNode(node)) { return (node.nodeName || '').toLowerCase(); } // Mocked nodes in testing environments may not be instances of Node. By // returning `#document` an infinite loop won't occur. // https://github.com/floating-ui/floating-ui/issues/2317 return '#document'; } function getWindow(node) { var _node$ownerDocument; return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window; } function getDocumentElement(node) { var _ref; return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement; } function isNode(value) { if (!hasWindow()) { return false; } return value instanceof Node || value instanceof getWindow(value).Node; } function isElement(value) { if (!hasWindow()) { return false; } return value instanceof Element || value instanceof getWindow(value).Element; } function isHTMLElement(value) { if (!hasWindow()) { return false; } return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement; } function isShadowRoot(value) { if (!hasWindow() || typeof ShadowRoot === 'undefined') { return false; } return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot; } function isWebKit() { if (typeof CSS === 'undefined' || !CSS.supports) return false; return CSS.supports('-webkit-backdrop-filter', 'none'); } function isLastTraversableNode(node) { return ['html', 'body', '#document'].includes(getNodeName(node)); } function getComputedStyle$1(element) { return getWindow(element).getComputedStyle(element); } function getParentNode(node) { if (getNodeName(node) === 'html') { return node; } const result = // Step into the shadow DOM of the parent of a slotted node. node.assignedSlot || // DOM Element detected. node.parentNode || // ShadowRoot detected. isShadowRoot(node) && node.host || // Fallback. getDocumentElement(node); return isShadowRoot(result) ? result.host : result; } 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; } // 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; } // 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 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/'); } 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); } function isReactEvent(event) { return 'nativeEvent' in event; } function isRootElement(element) { return element.matches('html,body'); } function getDocument(node) { return (node == null ? void 0 : node.ownerDocument) || document; } 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 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; } const TYPEABLE_SELECTOR = "input:not([type='hidden']):not([disabled])," + "[contenteditable]:not([contenteditable='false']),textarea:not([disabled])"; function isTypeableElement(element) { return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR); } function stopEvent(event) { event.preventDefault(); event.stopPropagation(); } function isTypeableCombobox(element) { if (!element) return false; return element.getAttribute('role') === 'combobox' && isTypeableElement(element); } /** * Custom positioning reference element. * @see https://floating-ui.com/docs/virtual-elements */ const min = Math.min; const max = Math.max; const round = Math.round; const floor = Math.floor; function evaluate(value, param) { return typeof value === 'function' ? value(param) : value; } const ARROW_UP = 'ArrowUp'; const ARROW_DOWN = 'ArrowDown'; const ARROW_LEFT = 'ArrowLeft'; const ARROW_RIGHT = 'ArrowRight'; function isDifferentRow(index, cols, prevRow) { return Math.floor(index / cols) !== prevRow; } function isIndexOutOfBounds(listRef, index) { return index < 0 || index >= listRef.current.length; } function getMinIndex(listRef, disabledIndices) { return findNonDisabledIndex(listRef, { disabledIndices }); } function getMaxIndex(listRef, disabledIndices) { return findNonDisabledIndex(listRef, { decrement: true, startingIndex: listRef.current.length, disabledIndices }); } function findNonDisabledIndex(listRef, _temp) { let { startingIndex = -1, decrement = false, disabledIndices, amount = 1 } = _temp === void 0 ? {} : _temp; const list = listRef.current; let index = startingIndex; do { index += decrement ? -amount : amount; } while (index >= 0 && index <= list.length - 1 && isDisabled(list, index, disabledIndices)); return index; } function getGridNavigatedIndex(elementsRef, _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 = findNonDisabledIndex(elementsRef, { 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 (isIndexOutOfBounds(elementsRef, nextIndex)) { nextIndex = prevIndex; } } if (event.key === ARROW_DOWN) { stop && stopEvent(event); if (prevIndex === -1) { nextIndex = minIndex; } else { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex, amount: cols, disabledIndices }); if (loop && prevIndex + cols > maxIndex) { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex % cols - cols, amount: cols, disabledIndices }); } } if (isIndexOutOfBounds(elementsRef, 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 = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex, disabledIndices }); if (loop && isDifferentRow(nextIndex, cols, prevRow)) { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex - prevIndex % cols - 1, disabledIndices }); } } else if (loop) { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex - prevIndex % cols - 1, disabledIndices }); } if (isDifferentRow(nextIndex, cols, prevRow)) { nextIndex = prevIndex; } } if (event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT)) { stop && stopEvent(event); if (prevIndex % cols !== 0) { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex, decrement: true, disabledIndices }); if (loop && isDifferentRow(nextIndex, cols, prevRow)) { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex + (cols - prevIndex % cols), decrement: true, disabledIndices }); } } else if (loop) { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: prevIndex + (cols - prevIndex % cols), decrement: true, disabledIndices }); } if (isDifferentRow(nextIndex, cols, prevRow)) { nextIndex = prevIndex; } } const lastRow = floor(maxIndex / cols) === prevRow; if (isIndexOutOfBounds(elementsRef, nextIndex)) { if (loop && lastRow) { nextIndex = event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT) ? maxIndex : findNonDisabledIndex(elementsRef, { startingIndex: prevIndex - prevIndex % cols - 1, disabledIndices }); } else { nextIndex = prevIndex; } } } return nextIndex; } /** For each cell index, gets the item index that occupies that cell */ function buildCellMap(sizes, cols, dense) { const cellMap = []; let startIndex = 0; sizes.forEach((_ref2, index) => { let { width, height } = _ref2; if (width > cols) { { 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 getCellIndexOfCorner(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 getCellIndices(indices, cellMap) { return cellMap.flatMap((index, cellIndex) => indices.includes(index) ? [cellIndex] : []); } function isDisabled(list, index, disabledIndices) { if (disabledIndices) { return disabledIndices.includes(index); } const element = list[index]; return element == null || element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true'; } var index = typeof document !== 'undefined' ? React.useLayoutEffect : React.useEffect; function sortByDocumentPosition(a, b) { const position = a.compareDocumentPosition(b); if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) { return -1; } if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) { return 1; } return 0; } function areMapsEqual(map1, map2) { if (map1.size !== map2.size) { return false; } for (const [key, value] of map1.entries()) { if (value !== map2.get(key)) { return false; } } return true; } const FloatingListContext = /*#__PURE__*/React__namespace.createContext({ register: () => {}, unregister: () => {}, map: /*#__PURE__*/new Map(), elementsRef: { current: [] } }); /** * Provides context for a list of items within the floating element. * @see https://floating-ui.com/docs/FloatingList */ function FloatingList(props) { const { children, elementsRef, labelsRef } = props; const [map, setMap] = React__namespace.useState(() => new Map()); const register = React__namespace.useCallback(node => { setMap(prevMap => new Map(prevMap).set(node, null)); }, []); const unregister = React__namespace.useCallback(node => { setMap(prevMap => { const map = new Map(prevMap); map.delete(node); return map; }); }, []); index(() => { const newMap = new Map(map); const nodes = Array.from(newMap.keys()).sort(sortByDocumentPosition); nodes.forEach((node, index) => { newMap.set(node, index); }); if (!areMapsEqual(map, newMap)) { setMap(newMap); } }, [map]); return /*#__PURE__*/React__namespace.createElement(FloatingListContext.Provider, { value: React__namespace.useMemo(() => ({ register, unregister, map, elementsRef, labelsRef }), [register, unregister, map, elementsRef, labelsRef]) }, children); } /** * Used to register a list item and its index (DOM position) in the * `FloatingList`. * @see https://floating-ui.com/docs/FloatingList#uselistitem */ function useListItem(props) { if (props === void 0) { props = {}; } const { label } = props; const { register, unregister, map, elementsRef, labelsRef } = React__namespace.useContext(FloatingListContext); const [index$1, setIndex] = React__namespace.useState(null); const componentRef = React__namespace.useRef(null); const ref = React__namespace.useCallback(node => { componentRef.current = node; if (index$1 !== null) { elementsRef.current[index$1] = node; if (labelsRef) { var _node$textContent; const isLabelDefined = label !== undefined; labelsRef.current[index$1] = isLabelDefined ? label : (_node$textContent = node == null ? void 0 : node.textContent) != null ? _node$textContent : null; } } }, [index$1, elementsRef, labelsRef, label]); index(() => { const node = componentRef.current; if (node) { register(node); return () => { unregister(node); }; } }, [register, unregister]); index(() => { const index = componentRef.current ? map.get(componentRef.current) : null; if (index != null) { setIndex(index); } }, [map]); return React__namespace.useMemo(() => ({ ref, index: index$1 == null ? -1 : index$1 }), [index$1, ref]); } function renderJsx(render, computedProps) { if (typeof render === 'function') { return render(computedProps); } if (render) { return /*#__PURE__*/React__namespace.cloneElement(render, computedProps); } return /*#__PURE__*/React__namespace.createElement("div", computedProps); } const CompositeContext = /*#__PURE__*/React__namespace.createContext({ activeIndex: 0, onNavigate: () => {} }); const horizontalKeys = [ARROW_LEFT, ARROW_RIGHT]; const verticalKeys = [ARROW_UP, ARROW_DOWN]; const allKeys = [...horizontalKeys, ...verticalKeys]; /** * Creates a single tab stop whose items are navigated by arrow keys, which * provides list navigation outside of floating element contexts. * * This is useful to enable navigation of a list of items that aren’t part of a * floating element. A menubar is an example of a composite, with each reference * element being an item. * @see https://floating-ui.com/docs/Composite */ const Composite = /*#__PURE__*/React__namespace.forwardRef(function Composite(props, forwardedRef) { const { render, orientation = 'both', loop = true, rtl = false, cols = 1, disabledIndices, activeIndex: externalActiveIndex, onNavigate: externalSetActiveIndex, itemSizes, dense = false, ...domProps } = props; const [internalActiveIndex, internalSetActiveIndex] = React__namespace.useState(0); const activeIndex = externalActiveIndex != null ? externalActiveIndex : internalActiveIndex; const onNavigate = useEffectEvent(externalSetActiveIndex != null ? externalSetActiveIndex : internalSetActiveIndex); const elementsRef = React__namespace.useRef([]); const renderElementProps = render && typeof render !== 'function' ? render.props : {}; const contextValue = React__namespace.useMemo(() => ({ activeIndex, onNavigate }), [activeIndex, onNavigate]); const isGrid = cols > 1; function handleKeyDown(event) { if (!allKeys.includes(event.key)) return; let nextIndex = activeIndex; const minIndex = getMinIndex(elementsRef, disabledIndices); const maxIndex = getMaxIndex(elementsRef, disabledIndices); const horizontalEndKey = rtl ? ARROW_LEFT : ARROW_RIGHT; const horizontalStartKey = rtl ? ARROW_RIGHT : ARROW_LEFT; if (isGrid) { const sizes = itemSizes || Array.from({ length: elementsRef.current.length }, () => ({ width: 1, height: 1 })); // To calculate movements on the grid, we use hypothetical cell indices // as if every item was 1x1, then convert back to real indices. const cellMap = buildCellMap(sizes, cols, dense); const minGridIndex = cellMap.findIndex(index => index != null && !isDisabled(elementsRef.current, index, disabledIndices)); // last enabled index const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !isDisabled(elementsRef.current, index, disabledIndices) ? cellIndex : foundIndex, -1); const maybeNextIndex = cellMap[getGridNavigatedIndex({ current: cellMap.map(itemIndex => itemIndex ? elementsRef.current[itemIndex] : null) }, { event, orientation, loop, rtl, cols, // treat undefined (empty grid spaces) as disabled indices so we // don't end up in them disabledIndices: getCellIndices([...(disabledIndices || elementsRef.current.map((_, index) => isDisabled(elementsRef.current, index) ? index : undefined)), undefined], cellMap), minIndex: minGridIndex, maxIndex: maxGridIndex, prevIndex: getCellIndexOfCorner(activeIndex > maxIndex ? minIndex : activeIndex, sizes, cellMap, cols, // use a corner matching the edge closest to the direction we're // moving in so we don't end up in the same item. Prefer // top/left over bottom/right. event.key === ARROW_DOWN ? 'bl' : event.key === horizontalEndKey ? 'tr' : 'tl') })]; if (maybeNextIndex != null) { nextIndex = maybeNextIndex; } } const toEndKeys = { horizontal: [horizontalEndKey], vertical: [ARROW_DOWN], both: [horizontalEndKey, ARROW_DOWN] }[orientation]; const toStartKeys = { horizontal: [horizontalStartKey], vertical: [ARROW_UP], both: [horizontalStartKey, ARROW_UP] }[orientation]; const preventedKeys = isGrid ? allKeys : { horizontal: horizontalKeys, vertical: verticalKeys, both: allKeys }[orientation]; if (nextIndex === activeIndex && [...toEndKeys, ...toStartKeys].includes(event.key)) { if (loop && nextIndex === maxIndex && toEndKeys.includes(event.key)) { nextIndex = minIndex; } else if (loop && nextIndex === minIndex && toStartKeys.includes(event.key)) { nextIndex = maxIndex; } else { nextIndex = findNonDisabledIndex(elementsRef, { startingIndex: nextIndex, decrement: toStartKeys.includes(event.key), disabledIndices }); } } if (nextIndex !== activeIndex && !isIndexOutOfBounds(elementsRef, nextIndex)) { var _elementsRef$current$; event.stopPropagation(); if (preventedKeys.includes(event.key)) { event.preventDefault(); } onNavigate(nextIndex); (_elementsRef$current$ = elementsRef.current[nextIndex]) == null || _elementsRef$current$.focus(); } } const computedProps = { ...domProps, ...renderElementProps, ref: forwardedRef, 'aria-orientation': orientation === 'both' ? undefined : orientation, onKeyDown(e) { domProps.onKeyDown == null || domProps.onKeyDown(e); renderElementProps.onKeyDown == null || renderElementProps.onKeyDown(e); handleKeyDown(e); } }; return /*#__PURE__*/React__namespace.createElement(CompositeContext.Provider, { value: contextValue }, /*#__PURE__*/React__namespace.createElement(FloatingList, { elementsRef: elementsRef }, renderJsx(render, computedProps))); }); /** * @see https://floating-ui.com/docs/Composite */ const CompositeItem = /*#__PURE__*/React__namespace.forwardRef(function CompositeItem(props, forwardedRef) { const { render, ...domProps } = props; const renderElementProps = render && typeof render !== 'function' ? render.props : {}; const { activeIndex, onNavigate } = React__namespace.useContext(CompositeContext); const { ref, index } = useListItem(); const mergedRef = useMergeRefs([ref, forwardedRef, renderElementProps.ref]); const isActive = activeIndex === index; const computedProps = { ...domProps, ...renderElementProps, ref: mergedRef, tabIndex: isActive ? 0 : -1, 'data-active': isActive ? '' : undefined, onFocus(e) { domProps.onFocus == null || domProps.onFocus(e); renderElementProps.onFocus == null || renderElementProps.onFocus(e); onNavigate(index); } }; return renderJsx(render, computedProps); }); function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } let serverHandoffComplete = false; let count = 0; const genId = () => // Ensure the id is unique with multiple independent versions of Floating UI // on serverHandoffComplete ? genId() : undefined); index(() => { if (id == null) { setId(genId()); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); React__namespace.useEffect(() => { serverHandoffComplete = true; }, []); return id; } const useReactId = SafeReact.useId; /** * Uses React 18's built-in `useId()` when available, or falls back to a * slightly less performant (requiring a double render) implementation for * earlier React versions. * @see https://floating-ui.com/docs/react-utils#useid */ const useId = useReactId || useFloatingId; let devMessageSet; { devMessageSet = /*#__PURE__*/new Set(); } function warn() { var _devMessageSet; for (var _len = arguments.length, messages = new Array(_len), _key = 0; _key < _len; _key++) { messages[_key] = arguments[_key]; } const message = "Floating UI: " + messages.join(' '); if (!((_devMessageSet = devMessageSet) != null && _devMessageSet.has(message))) { var _devMessageSet2; (_devMessageSet2 = devMessageSet) == null || _devMessageSet2.add(message); console.warn(message); } } function error() { var _devMessageSet3; for (var _len2 = arguments.length, messages = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { messages[_key2] = arguments[_key2]; } const message = "Floating UI: " + messages.join(' '); if (!((_devMessageSet3 = devMessageSet) != null && _devMessageSet3.has(message))) { var _devMessageSet4; (_devMessageSet4 = devMessageSet) == null || _devMessageSet4.add(message); console.error(message); } } /** * Renders a pointing arrow triangle. * @see https://floating-ui.com/docs/FloatingArrow */ const FloatingArrow = /*#__PURE__*/React__namespace.forwardRef(function FloatingArrow(props, ref) { const { context: { placement, elements: { floating }, middlewareData: { arrow, shift } }, width = 14, height = 7, tipRadius = 0, strokeWidth = 0, staticOffset, stroke, d, style: { transform, ...restStyle } = {}, ...rest } = props; { if (!ref) { warn('The `ref` prop is required for `FloatingArrow`.'); } } const clipPathId = useId(); const [isRTL, setIsRTL] = React__namespace.useState(false); // https://github.com/floating-ui/floating-ui/issues/2932 index(() => { if (!floating) return; const isRTL = getComputedStyle$1(floating).direction === 'rtl'; if (isRTL) { setIsRTL(true); } }, [floating]); if (!floating) { return null; } const [side, alignment] = placement.split('-'); const isVerticalSide = side === 'top' || side === 'bottom'; let computedStaticOffset = staticOffset; if (isVerticalSide && shift != null && shift.x || !isVerticalSide && shift != null && shift.y) { computedStaticOffset = null; } // Strokes must be double the border width, this ensures the stroke's width // works as you'd expect. const computedStrokeWidth = strokeWidth * 2; const halfStrokeWidth = computedStrokeWidth / 2; const svgX = width / 2 * (tipRadius / -8 + 1); const svgY = height / 2 * tipRadius / 4; const isCustomShape = !!d; const yOffsetProp = computedStaticOffset && alignment === 'end' ? 'bottom' : 'top'; let xOffsetProp = computedStaticOffset && alignment === 'end' ? 'right' : 'left'; if (computedStaticOffset && isRTL) { xOffsetProp = alignment === 'end' ? 'left' : 'right'; } const arrowX = (arrow == null ? void 0 : arrow.x) != null ? computedStaticOffset || arrow.x : ''; const arrowY = (arrow == null ? void 0 : arrow.y) != null ? computedStaticOffset || arrow.y : ''; const dValue = d || 'M0,0' + (" H" + width) + (" L" + (width - svgX) + "," + (height - svgY)) + (" Q" + width / 2 + "," + height + " " + svgX + "," + (height - svgY)) + ' Z'; const rotation = { top: isCustomShape ? 'rotate(180deg)' : '', left: isCustomShape ? 'rotate(90deg)' : 'rotate(-90deg)', bottom: isCustomShape ? '' : 'rotate(180deg)', right: isCustomShape ? 'rotate(-90deg)' : 'rotate(90deg)' }[side]; return /*#__PURE__*/React__namespace.createElement("svg", _extends({}, rest, { "aria-hidden": true, ref: ref, width: isCustomShape ? width : width + computedStrokeWidth, height: width, viewBox: "0 0 " + width + " " + (height > width ? height : width), style: { position: 'absolute', pointerEvents: 'none', [xOffsetProp]: arrowX, [yOffsetProp]: arrowY, [side]: isVerticalSide || isCustomShape ? '100%' : "calc(100% - " + computedStrokeWidth / 2 + "px)", transform: [rotation, transform].filter(t => !!t).join(' '), ...restStyle } }), computedStrokeWidth > 0 && /*#__PURE__*/React__namespace.createElement("path", { clipPath: "url(#" + clipPathId + ")", fill: "none", stroke: stroke // Account for the stroke on the fill path rendered below. , strokeWidth: computedStrokeWidth + (d ? 0 : 1), d: dValue }), /*#__PURE__*/React__namespace.createElement("path", { stroke: computedStrokeWidth && !d ? rest.fill : 'none', d: dValue }), /*#__PURE__*/React__namespace.createElement("clipPath", { id: clipPathId }, /*#__PURE__*/React__namespace.createElement("rect", { x: -halfStrokeWidth, y: halfStrokeWidth * (isCustomShape ? -1 : 1), width: width + computedStrokeWidth, height: width }))); }); function createPubSub() { const map = new Map(); return { emit(event, data) { var _map$get; (_map$get = map.get(event)) == null || _map$get.forEach(handler => handler(data)); }, on(event, listener) { map.set(event, [...(map.get(event) || []), listener]); }, off(event, listener) { var _map$get2; map.set(event, ((_map$get2 = map.get(event)) == null ? void 0 : _map$get2.filter(l => l !== listener)) || []); } }; } const FloatingNodeContext = /*#__PURE__*/React__namespace.createContext(null); const FloatingTreeContext = /*#__PURE__*/React__namespace.createContext(null); /** * Returns the parent node id for nested floating elements, if available. * Returns `null` for top-level floating elements. */ const useFloatingParentNodeId = () => { var _React$useContext; return ((_React$useContext = React__namespace.useContext(FloatingNodeContext)) == null ? void 0 : _React$useContext.id) || null; }; /** * Returns the nearest floating tree context, if available. */ const useFloatingTree = () => React__namespace.useContext(FloatingTreeContext); /** * Registers a node into the `FloatingTree`, returning its id. * @see https://floating-ui.com/docs/FloatingTree */ function useFloatingNodeId(customParentId) { const id = useId(); const tree = useFloatingTree(); const reactParentId = useFloatingParentNodeId(); const parentId = customParentId || reactParentId; index(() => { const node = { id, parentId }; tree == null || tree.addNode(node); return () => { tree == null || tree.removeNode(node); }; }, [tree, id, parentId]); return id; } /** * Provides parent node context for nested floating elements. * @see https://floating-ui.com/docs/FloatingTree */ function FloatingNode(props) { const { children, id } = props; const parentId = useFloatingParentNodeId(); return /*#__PURE__*/React__namespace.createElement(FloatingNodeContext.Provider, { value: React__namespace.useMemo(() => ({ id, parentId }), [id, parentId]) }, children); } /** * Provides context for nested floating elements when they are not children of * each other on the DOM. * This is not necessary in all cases, except when there must be explicit communication between parent and child floating elements. It is necessary for: * - The `bubbles` option in the `useDismiss()` Hook * - Nested virtual list navigation * - Nested floating elements that each open on hover * - Custom communication between parent and child floating elements * @see https://floating-ui.com/docs/FloatingTree */ function FloatingTree(props) { const { children } = props; const nodesRef = React__namespace.useRef([]); const addNode = React__namespace.useCallback(node => { nodesRef.current = [...nodesRef.current, node]; }, []); const removeNode = React__namespace.useCallback(node => { nodesRef.current = nodesRef.current.filter(n => n !== node); }, []); const events = React__namespace.useState(() => createPubSub())[0]; return /*#__PURE__*/React__namespace.createElement(FloatingTreeContext.Provider, { value: React__namespace.useMemo(() => ({ nodesRef, addNode, removeNode, events }), [addNode, removeNode, events]) }, children); } function createAttribute(name) { return "data-floating-ui-" + name; } function useLatestRef(value) { const ref = React.useRef(value); index(() => { ref.current = value; }); return ref; } const safePolygonIdentifier = /*#__PURE__*/createAttribute('safe-polygon'); function getDelay(value, prop, pointerType) { if (pointerType && !isMouseLikePointerType(pointerType)) { return 0; } if (typeof value === 'number') { return value; } return value == null ? void 0 : value[prop]; } /** * Opens the floating element while hovering over the reference element, like * CSS `:hover`. * @see https://floating-ui.com/docs/useHover */ function useHover(context, props) { if (props === void 0) { props = {}; } const { open, onOpenChange, dataRef, events, elements } = context; const { enabled = true, delay = 0, handleClose = null, mouseOnly = false, restMs = 0, move = true } = props; const tree = useFloatingTree(); const parentId = useFloatingParentNodeId(); const handleCloseRef = useLatestRef(handleClose); const delayRef = useLatestRef(delay); const openRef = useLatestRef(open); const pointerTypeRef = React__namespace.useRef(); const timeoutRef = React__namespace.useRef(-1); const handlerRef = React__namespace.useRef(); const restTimeoutRef = React__namespace.useRef(-1); const blockMouseMoveRef = React__namespace.useRef(true); const performedPointerEventsMutationRef = React__namespace.useRef(false); const unbindMouseMoveRef = React__namespace.useRef(() => {}); const restTimeoutPendingRef = React__namespace.useRef(false); const isHoverOpen = React__namespace.useCallback(() => { var _dataRef$current$open; const type = (_dataRef$current$open = dataRef.current.openEvent) == null ? void 0 : _dataRef$current$open.type; return (type == null ? void 0 : type.includes('mouse')) && type !== 'mousedown'; }, [dataRef]); // When closing before opening, clear the delay timeouts to cancel it // from showing. React__namespace.useEffect(() => { if (!enabled) return; function onOpenChange(_ref) { let { open } = _ref; if (!open) { clearTimeout(timeoutRef.current); clearTimeout(restTimeoutRef.current); blockMouseMoveRef.current = true; restTimeoutPendingRef.current = false; } } events.on('openchange', onOpenChange); return () => { events.off('openchange', onOpenChange); }; }, [enabled, events]); React__namespace.useEffect(() => { if (!enabled) return; if (!handleCloseRef.current) return; if (!open) return; function onLeave(event) { if (isHoverOpen()) { onOpenChange(false, event, 'hover'); } } const html = getDocument(elements.floating).documentElement; html.addEventListener('mouseleave', onLeave); return () => { html.removeEventListener('mouseleave', onLeave); }; }, [elements.floating, open, onOpenChange, enabled, handleCloseRef, isHoverOpen]); const closeWithDelay = React__namespace.useCallback(function (event, runElseBranch, reason) { if (runElseBranch === void 0) { runElseBranch = true; } if (reason === void 0) { reason = 'hover'; } const closeDelay = getDelay(delayRef.current, 'close', pointerTypeRef.current); if (closeDelay && !handlerRef.current) { clearTimeout(timeoutRef.current); timeoutRef.current = window.setTimeout(() => onOpenChange(false, event, reason), closeDelay); } else if (runElseBranch) { clearTimeout(timeoutRef.current); onOpenChange(false, event, reason); } }, [delayRef, onOpenChange]); const cleanupMouseMoveHandler = useEffectEvent(() => { unbindMouseMoveRef.current(); handlerRef.current = undefined; }); const clearPointerEvents = useEffectEvent(() => { if (performedPointerEventsMutationRef.current) { const body = getDocument(elements.floating).body; body.style.pointerEvents = ''; body.removeAttribute(safePolygonIdentifier); performedPointerEventsMutationRef.current = false; } }); const isClickLikeOpenEvent = useEffectEvent(() => { return dataRef.current.openEvent ? ['click', 'mousedown'].includes(dataRef.current.openEvent.type) : false; }); // Registering the mouse events on the reference directly to bypass React's // delegation system. If the cursor was on a disabled element and then entered // the reference (no gap), `mouseenter` doesn't fire in the delegation system. React__namespace.useEffect(() => { if (!enabled) return; function onMouseEnter(event) { clearTimeout(timeoutRef.current); blockMouseMoveRef.current = false; if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current) || restMs > 0 && !getDelay(delayRef.current, 'open')) { return; } const openDelay = getDelay(delayRef.current, 'open', pointerTypeRef.current); if (openDelay) { timeoutRef.current = window.setTimeout(() => { if (!openRef.current) { onOpenChange(true, event, 'hover'); } }, openDelay); } else if (!open) { onOpenChange(true, event, 'hover'); } } function onMouseLeave(event) { if (isClickLikeOpenEvent()) return; unbindMouseMoveRef.current(); const doc = getDocument(elements.floating); clearTimeout(restTimeoutRef.current); restTimeoutPendingRef.current = false; if (handleCloseRef.current && dataRef.current.floatingContext) { // Prevent clearing `onScrollMouseLeave` timeout. if (!open) { clearTimeout(timeoutRef.current); } handlerRef.current = handleCloseRef.current({ ...dataRef.current.floatingContext, tree, x: event.clientX, y: event.clientY, onClose() { clearPointerEvents(); cleanupMouseMoveHandler(); if (!isClickLikeOpenEvent()) { closeWithDelay(event, true, 'safe-polygon'); } } }); const handler = handlerRef.current; doc.addEventListener('mousemove', handler); unbindMouseMoveRef.current = () => { doc.removeEventListener('mousemove', handler); }; return; } // Allow interactivity without `safePolygon` on touch devices. With a // pointer, a short close delay is an alternative, so it should work // consistently. const shouldClose = pointerTypeRef.current === 'touch' ? !contains(elements.floating, event.relatedTarget) : true; if (shouldClose) { closeWithDelay(event); } } // Ensure the floating element closes after scrolling even if the pointer // did not move. // https://github.com/floating-ui/floating-ui/discussions/1692 function onScrollMouseLeave(event) { if (isClickLikeOpenEvent()) return; if (!dataRef.current.floatingContext) return; handleCloseRef.current == null || handleCloseRef.current({ ...dataRef.current.floatingContext, tree, x: event.clientX, y: event.clientY, onClose() { clearPointerEvents(); cleanupMouseMoveHandler(); if (!isClickLikeOpenEvent()) { closeWithDelay(event); } } })(event); } if (isElement(elements.domReference)) { var _elements$floating; const ref = elements.domReference; open && ref.addEventListener('mouseleave', onScrollMouseLeave); (_elements$floating = elements.floating) == null || _elements$floating.addEventListener('mouseleave', onScrollMouseLeave); move && ref.addEventListener('mousemove', onMouseEnter, { once: true }); ref.addEventListener('mouseenter', onMouseEnter); ref.addEventListener('mouseleave', onMouseLeave); return () => { var _elements$floating2; open && ref.removeEventListener('mouseleave', onScrollMouseLeave); (_elements$floating2 = elements.floating) == null || _elements$floating2.removeEventListener('mouseleave', onScrollMouseLeave); move && ref.removeEventListener('mousemove', onMouseEnter); ref.removeEventListener('mouseenter', onMouseEnter); ref.removeEventListener('mouseleave', onMouseLeave); }; } }, [elements, enabled, context, mouseOnly, restMs, move, closeWithDelay, cleanupMouseMoveHandler, clearPointerEvents, onOpenChange, open, openRef, tree, delayRef, handleCloseRef, dataRef, isClickLikeOpenEvent]); // Block pointer-events of every element other than the reference and floating // while the floating element is open and has a `handleClose` handler. Also // handles nested floating elements. // https://github.com/floating-ui/floating-ui/issues/1722 index(() => { var _handleCloseRef$curre; if (!enabled) return; if (open && (_handleCloseRef$curre = handleCloseRef.current) != null && _handleCloseRef$curre.__options.blockPointerEvents && isHoverOpen()) { performedPointerEventsMutationRef.current = true; const floatingEl = elements.floating; if (isElement(elements.domReference) && floatingEl) { var _tree$nodesRef$curren; const body = getDocument(elements.floating).body; body.setAttribute(safePolygonIdentifier, ''); const ref = elements.domReference; const parentFloating = tree == null || (_tree$nodesRef$curren = tree.nodesRef.current.find(node => node.id === parentId)) == null || (_tree$nodesRef$curren = _tree$nodesRef$curren.context) == null ? void 0 : _tree$nodesRef$curren.elements.floating; if (parentFloating) { parentFloating.style.pointerEvents = ''; } body.style.pointerEvents = 'none'; ref.style.pointerEvents = 'auto'; floatingEl.style.pointerEvents = 'auto'; return () => { body.style.pointerEvents = ''; ref.style.pointerEvents = ''; floatingEl.style.pointerEvents = ''; }; } } }, [enabled, open, parentId, elements, tree, handleCloseRef, isHoverOpen]); index(() => { if (!open) { pointerTypeRef.current = undefined; restTimeoutPendingRef.current = false; cleanupMouseMoveHandler(); clearPointerEvents(); } }, [open, cleanupMouseMoveHandler, clearPointerEvents]); React__namespace.useEffect(() => { return () => { cleanupMouseMoveHandler(); clearTimeout(timeoutRef.current); clearTimeout(restTimeoutRef.current); clearPointerEvents(); }; }, [enabled, elements.domReference, cleanupMouseMoveHandler, clearPointerEvents]); const reference = React__namespace.useMemo(() => { function setPointerRef(event) { pointerTypeRef.current = event.pointerType; } return { onPointerDown: setPointerRef, onPointerEnter: setPointerRef, onMouseMove(event) { const { nativeEvent } = event; function handleMouseMove() { if (!blockMouseMoveRef.current && !openRef.current) { onOpenChange(true, nativeEvent, 'hover'); } } if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current)) { return; } if (open || restMs === 0) { return; } // Ignore insignificant movements to account for tremors. if (restTimeoutPendingRef.current && event.movementX ** 2 + event.movementY ** 2 < 2) { return; } clearTimeout(restTimeoutRef.current); if (pointerTypeRef.current === 'touch') { handleMouseMove(); } else { restTimeoutPendingRef.current = true; restTimeoutRef.current = window.setTimeout(handleMouseMove, restMs); } } }; }, [mouseOnly, onOpenChange, open, openRef, restMs]); const floating = React__namespace.useMemo(() => ({ onMouseEnter() { clearTimeout(timeoutRef.current); }, onMouseLeave(event) { if (!isClickLikeOpenEvent()) { closeWithDelay(event.nativeEvent, false); } } }), [closeWithDelay, isClickLikeOpenEvent]); return React__namespace.useMemo(() => enabled ? { reference, floating } : {}, [enabled, reference, floating]); } const NOOP = () => {}; const FloatingDelayGroupContext = /*#__PURE__*/React__namespace.createContext({ delay: 0, initialDelay: 0, timeoutMs: 0, currentId: null, setCurrentId: NOOP, setState: NOOP, isInstantPhase: false }); /** * @deprecated * Use the return value of `useDelayGroup()` instead. */ const useDelayGroupContext = () => React__namespace.useContext(FloatingDelayGroupContext); /** * Provides context for a group of floating elements that should share a * `delay`. * @see https://floating-ui.com/docs/FloatingDelayGroup */ function FloatingDelayGroup(props) { const { children, delay, timeoutMs = 0 } = props; const [state, setState] = React__namespace.useReducer((prev, next) => ({ ...prev, ...next }), { delay, timeoutMs, initialDelay: delay, currentId: null, isInstantPhase: false }); const initialCurrentIdRef = React__namespace.useRef(null); const setCurrentId = React__namespace.useCallback(currentId => { setState({ currentId }); }, []); index(() => { if (state.currentId) { if (initialCurrentIdRef.current === null) { initialCurrentIdRef.current = state.currentId; } else if (!state.isInstantPhase) { setState({ isInstantPhase: true }); } } else { if (state.isInstantPhase) { setState({ isInstantPhase: false }); } initialCurrentIdRef.current = null; } }, [state.currentId, state.isInstantPhase]); return /*#__PURE__*/React__namespace.createElement(FloatingDelayGroupContext.Provider, { value: React__namespace.useMemo(() => ({ ...state, setState, setCurrentId }), [state, setCurrentId]) }, children); } /** * Enables grouping when called inside a component that's a child of a * `FloatingDelayGroup`. * @see https://floating-ui.com/docs/FloatingDelayGroup */ function useDelayGroup(context, options) { if (options === void 0) { options = {}; } const { open, onOpenChange, floatingId } = context; const { id: optionId, enabled = true } = options; const id = optionId != null ? optionId : floatingId; const groupContext = useDelayGroupContext(); const { currentId, setCurrentId, initialDelay, setState, timeoutMs } = groupContext; index(() => { if (!enabled) return; if (!currentId) return; setState({ delay: { open: 1, close: getDelay(initialDelay, 'close') } }); if (currentId !== id) { onOpenChange(false); } }, [enabled, id, onOpenChange, setState, currentId, initialDelay]); index(() => { function unset() { onOpenChange(false); setState({ delay: initialDelay, currentId: null }); } if (!enabled) return; if (!currentId) return; if (!open && currentId === id) { if (timeoutMs) { const timeout = window.setTimeout(unset, timeoutMs); return () => { clearTimeout(timeout); }; } unset(); } }, [enabled, open, setState, currentId, id, onOpenChange, initialDelay, timeoutMs]); index(() => { if (!enabled) return; if (setCurrentId === NOOP || !open) return; setCurrentId(id); }, [enabled, open, setCurrentId, id]); return groupContext; } /*! * tabbable 6.2.0 * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE */ // NOTE: separate `:not()` selectors has broader browser support than the newer // `:not([inert], [inert] *)` (Feb 2023) // CAREFUL: JSDom does not support `:not([inert] *)` as a selector; using it causes // the entire query to fail, resulting in no nodes found, which will break a lot // of things... so we have to rely on JS to identify nodes inside an inert container var candidateSelectors = ['input:not([inert])', 'select:not([inert])', 'textarea:not([inert])', 'a[href]:not([inert])', 'button:not([inert])', '[tabindex]:not(slot):not([inert])', 'audio[controls]:not([inert])', 'video[controls]:not([inert])', '[contenteditable]:not([contenteditable="false"]):not([inert])', 'details>summary:first-of-type:not([inert])', 'details:not([inert])']; var candidateSelector = /* #__PURE__ */candidateSelectors.join(','); var NoElement = typeof Element === 'undefined'; var matches = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; var getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) { var _element$getRootNode; return element === null || element === void 0 ? void 0 : (_element$getRootNode = element.getRootNode) === null || _element$getRootNode === void 0 ? void 0 : _element$getRootNode.call(element); } : function (element) { return element === null || element === void 0 ? void 0 : element.ownerDocument; }; /** * Determines if a node is inert or in an inert ancestor. * @param {Element} [node] * @param {boolean} [lookUp] If true and `node` is not inert, looks up at ancestors to * see if any of them are inert. If false, only `node` itself is considered. * @returns {boolean} True if inert itself or by way of being in an inert ancestor. * False if `node` is falsy. */ var isInert = function isInert(node, lookUp) { var _node$getAttribute; if (lookUp === void 0) { lookUp = true; } // CAREFUL: JSDom does not support inert at all, so we can't use the `HTMLElement.inert` // JS API property; we have to check the attribute, which can either be empty or 'true'; // if it's `null` (not specified) or 'false', it's an active element var inertAtt = node === null || node === void 0 ? void 0 : (_node$getAttribute = node.getAttribute) === null || _node$getAttribute === void 0 ? void 0 : _node$getAttribute.call(node, 'inert'); var inert = inertAtt === '' || inertAtt === 'true'; // NOTE: this could also be handled with `node.matches('[inert], :is([inert] *)')` // if it weren't for `matches()` not being a function on shadow roots; the following // code works for any kind of node // CAREFUL: JSDom does not appear to support certain selectors like `:not([inert] *)` // so it likely would not support `:is([inert] *)` either... var result = inert || lookUp && node && isInert(node.parentNode); // recursive return result; }; /** * Determines if a node's content is editable. * @param {Element} [node] * @returns True if it's content-editable; false if it's not or `node` is falsy. */ var isContentEditable = function isContentEditable(node) { var _node$getAttribute2; // CAREFUL: JSDom does not support the `HTMLElement.isContentEditable` API so we have // to use the attribute directly to check for this, which can either be empty or 'true'; // if it's `null` (not specified) or 'false', it's a non-editable element var attValue = node === null || node === void 0 ? void 0 : (_node$getAttribute2 = node.getAttribute) === null || _node$getAttribute2 === void 0 ? void 0 : _node$getAttribute2.call(node, 'contenteditable'); return attValue === '' || attValue === 'true'; }; /** * @param {Element} el container to check in * @param {boolean} includeContainer add container to check * @param {(node: Element) => boolean} filter filter candidates * @returns {Element[]} */ var getCandidates = function getCandidates(el, includeContainer, filter) { // even if `includeContainer=false`, we still have to check it for inertness because // if it's inert, all its children are inert if (isInert(el)) { return []; } var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector)); if (includeContainer && matches.call(el, candidateSelector)) { candidates.unshift(el); } candidates = candidates.filter(filter); return candidates; }; /** * @callback GetShadowRoot * @param {Element} element to check for shadow root * @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available. */ /** * @callback ShadowRootFilter * @param {Element} shadowHostNode the element which contains shadow content * @returns {boolean} true if a shadow root could potentially contain valid candidates. */ /** * @typedef {Object} CandidateScope * @property {Element} scopeParent contains inner candidates * @property {Element[]} candidates list of candidates found in the scope parent */ /** * @typedef {Object} IterativeOptions * @property {GetShadowRoot|boolean} getShadowRoot true if shadow support is enabled; falsy if not; * if a function, implies shadow support is enabled and either returns the shadow root of an element * or a boolean stating if it has an undisclosed shadow root * @property {(node: Element) => boolean} filter filter candidates * @property {boolean} flatten if true then result will flatten any CandidateScope into the returned list * @property {ShadowRootFilter} shadowRootFilter filter shadow roots; */ /** * @param {Element[]} elements list of element containers to match candidates from * @param {boolean} includeContainer add container list to check * @param {IterativeOptions} options * @returns {Array.} */ var getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) { var candidates = []; var elementsToCheck = Array.from(elements); while (elementsToCheck.length) { var element = elementsToCheck.shift(); if (isInert(element, false)) { // no need to look up since we're drilling down // anything inside this container will also be inert continue; } if (element.tagName === 'SLOT') { // add shadow dom slot scope (slot itself cannot be focusable) var assigned = element.assignedElements(); var content = assigned.length ? assigned : element.children; var nestedCandidates = getCandidatesIteratively(content, true, options); if (options.flatten) { candidates.push.apply(candidates, nestedCandidates); } else { candidates.push({ scopeParent: element, candidates: nestedCandidates }); } } else { // check candidate element var validCandidate = matches.call(element, candidateSelector); if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) { candidates.push(element); } // iterate over shadow content if possible var shadowRoot = element.shadowRoot || // check for an undisclosed shadow typeof options.getShadowRoot === 'function' && options.getShadowRoot(element); // no inert look up because we're already drilling down and checking for inertness // on the way down, so all containers to this root node should have already been // vetted as non-inert var validShadowRoot = !isInert(shadowRoot, false) && (!options.shadowRootFilter || options.shadowRootFilter(element)); if (shadowRoot && validShadowRoot) { // add shadow dom scope IIF a shadow root node was given; otherwise, an undisclosed // shadow exists, so look at light dom children as fallback BUT create a scope for any // child candidates found because they're likely slotted elements (elements that are // children of the web component element (which has the shadow), in the light dom, but // slotted somewhere _inside_ the undisclosed shadow) -- the scope is created below, // _after_ we return from this recursive call var _nestedCandidates = getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options); if (options.flatten) { candidates.push.apply(candidates, _nestedCandidates); } else { candidates.push({ scopeParent: element, candidates: _nestedCandidates }); } } else { // there's not shadow so just dig into the element's (light dom) children // __without__ giving the element special scope treatment elementsToCheck.unshift.apply(elementsToCheck, element.children); } } } return candidates; }; /** * @private * Determines if the node has an explicitly specified `tabindex` attribute. * @param {HTMLElement} node * @returns {boolean} True if so; false if not. */ var hasTabIndex = function hasTabIndex(node) { return !isNaN(parseInt(node.getAttribute('tabindex'), 10)); }; /** * Determine the tab index of a given node. * @param {HTMLElement} node * @returns {number} Tab order (negative, 0, or positive number). * @throws {Error} If `node` is falsy. */ var getTabIndex = function getTabIndex(node) { if (!node) { throw new Error('No node provided'); } if (node.tabIndex < 0) { // in Chrome,
,