| import { rectToClientRect, detectOverflow as detectOverflow$1, offset as offset$1, autoPlacement as autoPlacement$1, shift as shift$1, flip as flip$1, size as size$1, hide as hide$1, arrow as arrow$1, inline as inline$1, limitShift as limitShift$1, computePosition as computePosition$1 } from '@floating-ui/core'; |
| import { round, createCoords, max, min, floor } from '@floating-ui/utils'; |
| import { getComputedStyle, isHTMLElement, isElement, getWindow, isWebKit, getFrameElement, getNodeScroll, getDocumentElement, isTopLayer, getNodeName, isOverflowElement, getOverflowAncestors, getParentNode, isLastTraversableNode, isContainingBlock, isTableElement, getContainingBlock } from '@floating-ui/utils/dom'; |
| export { getOverflowAncestors } from '@floating-ui/utils/dom'; |
|
|
| function getCssDimensions(element) { |
| const css = getComputedStyle(element); |
| |
| |
| let width = parseFloat(css.width) || 0; |
| let height = parseFloat(css.height) || 0; |
| const hasOffset = isHTMLElement(element); |
| const offsetWidth = hasOffset ? element.offsetWidth : width; |
| const offsetHeight = hasOffset ? element.offsetHeight : height; |
| const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight; |
| if (shouldFallback) { |
| width = offsetWidth; |
| height = offsetHeight; |
| } |
| return { |
| width, |
| height, |
| $: shouldFallback |
| }; |
| } |
|
|
| function unwrapElement(element) { |
| return !isElement(element) ? element.contextElement : element; |
| } |
|
|
| function getScale(element) { |
| const domElement = unwrapElement(element); |
| if (!isHTMLElement(domElement)) { |
| return createCoords(1); |
| } |
| const rect = domElement.getBoundingClientRect(); |
| const { |
| width, |
| height, |
| $ |
| } = getCssDimensions(domElement); |
| let x = ($ ? round(rect.width) : rect.width) / width; |
| let y = ($ ? round(rect.height) : rect.height) / height; |
|
|
| |
|
|
| if (!x || !Number.isFinite(x)) { |
| x = 1; |
| } |
| if (!y || !Number.isFinite(y)) { |
| y = 1; |
| } |
| return { |
| x, |
| y |
| }; |
| } |
|
|
| const noOffsets = createCoords(0); |
| function getVisualOffsets(element) { |
| const win = getWindow(element); |
| if (!isWebKit() || !win.visualViewport) { |
| return noOffsets; |
| } |
| return { |
| x: win.visualViewport.offsetLeft, |
| y: win.visualViewport.offsetTop |
| }; |
| } |
| function shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) { |
| if (isFixed === void 0) { |
| isFixed = false; |
| } |
| if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow(element)) { |
| return false; |
| } |
| return isFixed; |
| } |
|
|
| function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) { |
| if (includeScale === void 0) { |
| includeScale = false; |
| } |
| if (isFixedStrategy === void 0) { |
| isFixedStrategy = false; |
| } |
| const clientRect = element.getBoundingClientRect(); |
| const domElement = unwrapElement(element); |
| let scale = createCoords(1); |
| if (includeScale) { |
| if (offsetParent) { |
| if (isElement(offsetParent)) { |
| scale = getScale(offsetParent); |
| } |
| } else { |
| scale = getScale(element); |
| } |
| } |
| const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0); |
| let x = (clientRect.left + visualOffsets.x) / scale.x; |
| let y = (clientRect.top + visualOffsets.y) / scale.y; |
| let width = clientRect.width / scale.x; |
| let height = clientRect.height / scale.y; |
| if (domElement) { |
| const win = getWindow(domElement); |
| const offsetWin = offsetParent && isElement(offsetParent) ? getWindow(offsetParent) : offsetParent; |
| let currentWin = win; |
| let currentIFrame = getFrameElement(currentWin); |
| while (currentIFrame && offsetParent && offsetWin !== currentWin) { |
| const iframeScale = getScale(currentIFrame); |
| const iframeRect = currentIFrame.getBoundingClientRect(); |
| const css = getComputedStyle(currentIFrame); |
| const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x; |
| const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y; |
| x *= iframeScale.x; |
| y *= iframeScale.y; |
| width *= iframeScale.x; |
| height *= iframeScale.y; |
| x += left; |
| y += top; |
| currentWin = getWindow(currentIFrame); |
| currentIFrame = getFrameElement(currentWin); |
| } |
| } |
| return rectToClientRect({ |
| width, |
| height, |
| x, |
| y |
| }); |
| } |
|
|
| |
| |
| function getWindowScrollBarX(element, rect) { |
| const leftScroll = getNodeScroll(element).scrollLeft; |
| if (!rect) { |
| return getBoundingClientRect(getDocumentElement(element)).left + leftScroll; |
| } |
| return rect.left + leftScroll; |
| } |
|
|
| function getHTMLOffset(documentElement, scroll, ignoreScrollbarX) { |
| if (ignoreScrollbarX === void 0) { |
| ignoreScrollbarX = false; |
| } |
| const htmlRect = documentElement.getBoundingClientRect(); |
| const x = htmlRect.left + scroll.scrollLeft - (ignoreScrollbarX ? 0 : |
| |
| getWindowScrollBarX(documentElement, htmlRect)); |
| const y = htmlRect.top + scroll.scrollTop; |
| return { |
| x, |
| y |
| }; |
| } |
|
|
| function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) { |
| let { |
| elements, |
| rect, |
| offsetParent, |
| strategy |
| } = _ref; |
| const isFixed = strategy === 'fixed'; |
| const documentElement = getDocumentElement(offsetParent); |
| const topLayer = elements ? isTopLayer(elements.floating) : false; |
| if (offsetParent === documentElement || topLayer && isFixed) { |
| return rect; |
| } |
| let scroll = { |
| scrollLeft: 0, |
| scrollTop: 0 |
| }; |
| let scale = createCoords(1); |
| const offsets = createCoords(0); |
| const isOffsetParentAnElement = isHTMLElement(offsetParent); |
| if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { |
| if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) { |
| scroll = getNodeScroll(offsetParent); |
| } |
| if (isHTMLElement(offsetParent)) { |
| const offsetRect = getBoundingClientRect(offsetParent); |
| scale = getScale(offsetParent); |
| offsets.x = offsetRect.x + offsetParent.clientLeft; |
| offsets.y = offsetRect.y + offsetParent.clientTop; |
| } |
| } |
| const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll, true) : createCoords(0); |
| return { |
| width: rect.width * scale.x, |
| height: rect.height * scale.y, |
| x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x, |
| y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y |
| }; |
| } |
|
|
| function getClientRects(element) { |
| return Array.from(element.getClientRects()); |
| } |
|
|
| |
| |
| function getDocumentRect(element) { |
| const html = getDocumentElement(element); |
| const scroll = getNodeScroll(element); |
| const body = element.ownerDocument.body; |
| const width = max(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth); |
| const height = max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight); |
| let x = -scroll.scrollLeft + getWindowScrollBarX(element); |
| const y = -scroll.scrollTop; |
| if (getComputedStyle(body).direction === 'rtl') { |
| x += max(html.clientWidth, body.clientWidth) - width; |
| } |
| return { |
| width, |
| height, |
| x, |
| y |
| }; |
| } |
|
|
| function getViewportRect(element, strategy) { |
| const win = getWindow(element); |
| const html = getDocumentElement(element); |
| const visualViewport = win.visualViewport; |
| let width = html.clientWidth; |
| let height = html.clientHeight; |
| let x = 0; |
| let y = 0; |
| if (visualViewport) { |
| width = visualViewport.width; |
| height = visualViewport.height; |
| const visualViewportBased = isWebKit(); |
| if (!visualViewportBased || visualViewportBased && strategy === 'fixed') { |
| x = visualViewport.offsetLeft; |
| y = visualViewport.offsetTop; |
| } |
| } |
| return { |
| width, |
| height, |
| x, |
| y |
| }; |
| } |
|
|
| |
| function getInnerBoundingClientRect(element, strategy) { |
| const clientRect = getBoundingClientRect(element, true, strategy === 'fixed'); |
| const top = clientRect.top + element.clientTop; |
| const left = clientRect.left + element.clientLeft; |
| const scale = isHTMLElement(element) ? getScale(element) : createCoords(1); |
| const width = element.clientWidth * scale.x; |
| const height = element.clientHeight * scale.y; |
| const x = left * scale.x; |
| const y = top * scale.y; |
| return { |
| width, |
| height, |
| x, |
| y |
| }; |
| } |
| function getClientRectFromClippingAncestor(element, clippingAncestor, strategy) { |
| let rect; |
| if (clippingAncestor === 'viewport') { |
| rect = getViewportRect(element, strategy); |
| } else if (clippingAncestor === 'document') { |
| rect = getDocumentRect(getDocumentElement(element)); |
| } else if (isElement(clippingAncestor)) { |
| rect = getInnerBoundingClientRect(clippingAncestor, strategy); |
| } else { |
| const visualOffsets = getVisualOffsets(element); |
| rect = { |
| x: clippingAncestor.x - visualOffsets.x, |
| y: clippingAncestor.y - visualOffsets.y, |
| width: clippingAncestor.width, |
| height: clippingAncestor.height |
| }; |
| } |
| return rectToClientRect(rect); |
| } |
| function hasFixedPositionAncestor(element, stopNode) { |
| const parentNode = getParentNode(element); |
| if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) { |
| return false; |
| } |
| return getComputedStyle(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode); |
| } |
|
|
| |
| |
| |
| function getClippingElementAncestors(element, cache) { |
| const cachedResult = cache.get(element); |
| if (cachedResult) { |
| return cachedResult; |
| } |
| let result = getOverflowAncestors(element, [], false).filter(el => isElement(el) && getNodeName(el) !== 'body'); |
| let currentContainingBlockComputedStyle = null; |
| const elementIsFixed = getComputedStyle(element).position === 'fixed'; |
| let currentNode = elementIsFixed ? getParentNode(element) : element; |
|
|
| |
| while (isElement(currentNode) && !isLastTraversableNode(currentNode)) { |
| const computedStyle = getComputedStyle(currentNode); |
| const currentNodeIsContaining = isContainingBlock(currentNode); |
| if (!currentNodeIsContaining && computedStyle.position === 'fixed') { |
| currentContainingBlockComputedStyle = null; |
| } |
| const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === 'static' && !!currentContainingBlockComputedStyle && ['absolute', 'fixed'].includes(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode); |
| if (shouldDropCurrentNode) { |
| |
| result = result.filter(ancestor => ancestor !== currentNode); |
| } else { |
| |
| currentContainingBlockComputedStyle = computedStyle; |
| } |
| currentNode = getParentNode(currentNode); |
| } |
| cache.set(element, result); |
| return result; |
| } |
|
|
| |
| |
| function getClippingRect(_ref) { |
| let { |
| element, |
| boundary, |
| rootBoundary, |
| strategy |
| } = _ref; |
| const elementClippingAncestors = boundary === 'clippingAncestors' ? isTopLayer(element) ? [] : getClippingElementAncestors(element, this._c) : [].concat(boundary); |
| const clippingAncestors = [...elementClippingAncestors, rootBoundary]; |
| const firstClippingAncestor = clippingAncestors[0]; |
| const clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => { |
| const rect = getClientRectFromClippingAncestor(element, clippingAncestor, strategy); |
| accRect.top = max(rect.top, accRect.top); |
| accRect.right = min(rect.right, accRect.right); |
| accRect.bottom = min(rect.bottom, accRect.bottom); |
| accRect.left = max(rect.left, accRect.left); |
| return accRect; |
| }, getClientRectFromClippingAncestor(element, firstClippingAncestor, strategy)); |
| return { |
| width: clippingRect.right - clippingRect.left, |
| height: clippingRect.bottom - clippingRect.top, |
| x: clippingRect.left, |
| y: clippingRect.top |
| }; |
| } |
|
|
| function getDimensions(element) { |
| const { |
| width, |
| height |
| } = getCssDimensions(element); |
| return { |
| width, |
| height |
| }; |
| } |
|
|
| function getRectRelativeToOffsetParent(element, offsetParent, strategy) { |
| const isOffsetParentAnElement = isHTMLElement(offsetParent); |
| const documentElement = getDocumentElement(offsetParent); |
| const isFixed = strategy === 'fixed'; |
| const rect = getBoundingClientRect(element, true, isFixed, offsetParent); |
| let scroll = { |
| scrollLeft: 0, |
| scrollTop: 0 |
| }; |
| const offsets = createCoords(0); |
| if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { |
| if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) { |
| scroll = getNodeScroll(offsetParent); |
| } |
| if (isOffsetParentAnElement) { |
| const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent); |
| offsets.x = offsetRect.x + offsetParent.clientLeft; |
| offsets.y = offsetRect.y + offsetParent.clientTop; |
| } else if (documentElement) { |
| |
| |
| offsets.x = getWindowScrollBarX(documentElement); |
| } |
| } |
| const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0); |
| const x = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x; |
| const y = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y; |
| return { |
| x, |
| y, |
| width: rect.width, |
| height: rect.height |
| }; |
| } |
|
|
| function isStaticPositioned(element) { |
| return getComputedStyle(element).position === 'static'; |
| } |
|
|
| function getTrueOffsetParent(element, polyfill) { |
| if (!isHTMLElement(element) || getComputedStyle(element).position === 'fixed') { |
| return null; |
| } |
| if (polyfill) { |
| return polyfill(element); |
| } |
| let rawOffsetParent = element.offsetParent; |
|
|
| |
| |
| |
| |
| if (getDocumentElement(element) === rawOffsetParent) { |
| rawOffsetParent = rawOffsetParent.ownerDocument.body; |
| } |
| return rawOffsetParent; |
| } |
|
|
| |
| |
| function getOffsetParent(element, polyfill) { |
| const win = getWindow(element); |
| if (isTopLayer(element)) { |
| return win; |
| } |
| if (!isHTMLElement(element)) { |
| let svgOffsetParent = getParentNode(element); |
| while (svgOffsetParent && !isLastTraversableNode(svgOffsetParent)) { |
| if (isElement(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) { |
| return svgOffsetParent; |
| } |
| svgOffsetParent = getParentNode(svgOffsetParent); |
| } |
| return win; |
| } |
| let offsetParent = getTrueOffsetParent(element, polyfill); |
| while (offsetParent && isTableElement(offsetParent) && isStaticPositioned(offsetParent)) { |
| offsetParent = getTrueOffsetParent(offsetParent, polyfill); |
| } |
| if (offsetParent && isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !isContainingBlock(offsetParent)) { |
| return win; |
| } |
| return offsetParent || getContainingBlock(element) || win; |
| } |
|
|
| const getElementRects = async function (data) { |
| const getOffsetParentFn = this.getOffsetParent || getOffsetParent; |
| const getDimensionsFn = this.getDimensions; |
| const floatingDimensions = await getDimensionsFn(data.floating); |
| return { |
| reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy), |
| floating: { |
| x: 0, |
| y: 0, |
| width: floatingDimensions.width, |
| height: floatingDimensions.height |
| } |
| }; |
| }; |
|
|
| function isRTL(element) { |
| return getComputedStyle(element).direction === 'rtl'; |
| } |
|
|
| const platform = { |
| convertOffsetParentRelativeRectToViewportRelativeRect, |
| getDocumentElement, |
| getClippingRect, |
| getOffsetParent, |
| getElementRects, |
| getClientRects, |
| getDimensions, |
| getScale, |
| isElement, |
| isRTL |
| }; |
|
|
| function rectsAreEqual(a, b) { |
| return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height; |
| } |
|
|
| |
| function observeMove(element, onMove) { |
| let io = null; |
| let timeoutId; |
| const root = getDocumentElement(element); |
| function cleanup() { |
| var _io; |
| clearTimeout(timeoutId); |
| (_io = io) == null || _io.disconnect(); |
| io = null; |
| } |
| function refresh(skip, threshold) { |
| if (skip === void 0) { |
| skip = false; |
| } |
| if (threshold === void 0) { |
| threshold = 1; |
| } |
| cleanup(); |
| const elementRectForRootMargin = element.getBoundingClientRect(); |
| const { |
| left, |
| top, |
| width, |
| height |
| } = elementRectForRootMargin; |
| if (!skip) { |
| onMove(); |
| } |
| if (!width || !height) { |
| return; |
| } |
| const insetTop = floor(top); |
| const insetRight = floor(root.clientWidth - (left + width)); |
| const insetBottom = floor(root.clientHeight - (top + height)); |
| const insetLeft = floor(left); |
| const rootMargin = -insetTop + "px " + -insetRight + "px " + -insetBottom + "px " + -insetLeft + "px"; |
| const options = { |
| rootMargin, |
| threshold: max(0, min(1, threshold)) || 1 |
| }; |
| let isFirstUpdate = true; |
| function handleObserve(entries) { |
| const ratio = entries[0].intersectionRatio; |
| if (ratio !== threshold) { |
| if (!isFirstUpdate) { |
| return refresh(); |
| } |
| if (!ratio) { |
| |
| |
| timeoutId = setTimeout(() => { |
| refresh(false, 1e-7); |
| }, 1000); |
| } else { |
| refresh(false, ratio); |
| } |
| } |
| if (ratio === 1 && !rectsAreEqual(elementRectForRootMargin, element.getBoundingClientRect())) { |
| |
| |
| |
| |
| |
| |
| |
| refresh(); |
| } |
| isFirstUpdate = false; |
| } |
|
|
| |
| |
| try { |
| io = new IntersectionObserver(handleObserve, { |
| ...options, |
| |
| root: root.ownerDocument |
| }); |
| } catch (e) { |
| io = new IntersectionObserver(handleObserve, options); |
| } |
| io.observe(element); |
| } |
| refresh(true); |
| return cleanup; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| function autoUpdate(reference, floating, update, options) { |
| if (options === void 0) { |
| options = {}; |
| } |
| const { |
| ancestorScroll = true, |
| ancestorResize = true, |
| elementResize = typeof ResizeObserver === 'function', |
| layoutShift = typeof IntersectionObserver === 'function', |
| animationFrame = false |
| } = options; |
| const referenceEl = unwrapElement(reference); |
| const ancestors = ancestorScroll || ancestorResize ? [...(referenceEl ? getOverflowAncestors(referenceEl) : []), ...getOverflowAncestors(floating)] : []; |
| ancestors.forEach(ancestor => { |
| ancestorScroll && ancestor.addEventListener('scroll', update, { |
| passive: true |
| }); |
| ancestorResize && ancestor.addEventListener('resize', update); |
| }); |
| const cleanupIo = referenceEl && layoutShift ? observeMove(referenceEl, update) : null; |
| let reobserveFrame = -1; |
| let resizeObserver = null; |
| if (elementResize) { |
| resizeObserver = new ResizeObserver(_ref => { |
| let [firstEntry] = _ref; |
| if (firstEntry && firstEntry.target === referenceEl && resizeObserver) { |
| |
| |
| resizeObserver.unobserve(floating); |
| cancelAnimationFrame(reobserveFrame); |
| reobserveFrame = requestAnimationFrame(() => { |
| var _resizeObserver; |
| (_resizeObserver = resizeObserver) == null || _resizeObserver.observe(floating); |
| }); |
| } |
| update(); |
| }); |
| if (referenceEl && !animationFrame) { |
| resizeObserver.observe(referenceEl); |
| } |
| resizeObserver.observe(floating); |
| } |
| let frameId; |
| let prevRefRect = animationFrame ? getBoundingClientRect(reference) : null; |
| if (animationFrame) { |
| frameLoop(); |
| } |
| function frameLoop() { |
| const nextRefRect = getBoundingClientRect(reference); |
| if (prevRefRect && !rectsAreEqual(prevRefRect, nextRefRect)) { |
| update(); |
| } |
| prevRefRect = nextRefRect; |
| frameId = requestAnimationFrame(frameLoop); |
| } |
| update(); |
| return () => { |
| var _resizeObserver2; |
| ancestors.forEach(ancestor => { |
| ancestorScroll && ancestor.removeEventListener('scroll', update); |
| ancestorResize && ancestor.removeEventListener('resize', update); |
| }); |
| cleanupIo == null || cleanupIo(); |
| (_resizeObserver2 = resizeObserver) == null || _resizeObserver2.disconnect(); |
| resizeObserver = null; |
| if (animationFrame) { |
| cancelAnimationFrame(frameId); |
| } |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| const detectOverflow = detectOverflow$1; |
|
|
| |
| |
| |
| |
| |
| |
| |
| const offset = offset$1; |
|
|
| |
| |
| |
| |
| |
| |
| const autoPlacement = autoPlacement$1; |
|
|
| |
| |
| |
| |
| |
| const shift = shift$1; |
|
|
| |
| |
| |
| |
| |
| |
| const flip = flip$1; |
|
|
| |
| |
| |
| |
| |
| |
| const size = size$1; |
|
|
| |
| |
| |
| |
| |
| const hide = hide$1; |
|
|
| |
| |
| |
| |
| |
| const arrow = arrow$1; |
|
|
| |
| |
| |
| |
| |
| const inline = inline$1; |
|
|
| |
| |
| |
| const limitShift = limitShift$1; |
|
|
| |
| |
| |
| |
| const computePosition = (reference, floating, options) => { |
| |
| |
| |
| const cache = new Map(); |
| const mergedOptions = { |
| platform, |
| ...options |
| }; |
| const platformWithCache = { |
| ...mergedOptions.platform, |
| _c: cache |
| }; |
| return computePosition$1(reference, floating, { |
| ...mergedOptions, |
| platform: platformWithCache |
| }); |
| }; |
|
|
| export { arrow, autoPlacement, autoUpdate, computePosition, detectOverflow, flip, hide, inline, limitShift, offset, platform, shift, size }; |
|
|