123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900 |
- 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';
- /**
- * 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;
- const createCoords = v => ({
- x: v,
- y: v
- });
- 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 isOverflowElement(element) {
- const {
- overflow,
- overflowX,
- overflowY,
- display
- } = getComputedStyle(element);
- return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !['inline', 'contents'].includes(display);
- }
- function isTableElement(element) {
- return ['table', 'td', 'th'].includes(getNodeName(element));
- }
- function isTopLayer(element) {
- return [':popover-open', ':modal'].some(selector => {
- try {
- return element.matches(selector);
- } catch (e) {
- return false;
- }
- });
- }
- function isContainingBlock(elementOrCss) {
- const webkit = isWebKit();
- const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;
- // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
- return css.transform !== 'none' || css.perspective !== 'none' || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || ['transform', 'perspective', 'filter'].some(value => (css.willChange || '').includes(value)) || ['paint', 'layout', 'strict', 'content'].some(value => (css.contain || '').includes(value));
- }
- function getContainingBlock(element) {
- let currentNode = getParentNode(element);
- while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
- if (isContainingBlock(currentNode)) {
- return currentNode;
- } else if (isTopLayer(currentNode)) {
- return null;
- }
- currentNode = getParentNode(currentNode);
- }
- return null;
- }
- 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(element) {
- return getWindow(element).getComputedStyle(element);
- }
- function getNodeScroll(element) {
- if (isElement(element)) {
- return {
- scrollLeft: element.scrollLeft,
- scrollTop: element.scrollTop
- };
- }
- return {
- scrollLeft: element.scrollX,
- scrollTop: element.scrollY
- };
- }
- 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 getNearestOverflowAncestor(node) {
- const parentNode = getParentNode(node);
- if (isLastTraversableNode(parentNode)) {
- return node.ownerDocument ? node.ownerDocument.body : node.body;
- }
- if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
- return parentNode;
- }
- return getNearestOverflowAncestor(parentNode);
- }
- function getOverflowAncestors(node, list, traverseIframes) {
- var _node$ownerDocument2;
- if (list === void 0) {
- list = [];
- }
- if (traverseIframes === void 0) {
- traverseIframes = true;
- }
- const scrollableAncestor = getNearestOverflowAncestor(node);
- const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
- const win = getWindow(scrollableAncestor);
- if (isBody) {
- const frameElement = getFrameElement(win);
- return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
- }
- return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
- }
- function getFrameElement(win) {
- return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
- }
- function getCssDimensions(element) {
- const css = getComputedStyle(element);
- // In testing environments, the `width` and `height` properties are empty
- // strings for SVG elements, returning NaN. Fallback to `0` in this case.
- 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;
- // 0, NaN, or Infinity should always fallback to 1.
- if (!x || !Number.isFinite(x)) {
- x = 1;
- }
- if (!y || !Number.isFinite(y)) {
- y = 1;
- }
- return {
- x,
- y
- };
- }
- const noOffsets = /*#__PURE__*/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
- });
- }
- // If <html> has a CSS width greater than the viewport, then this will be
- // incorrect for RTL.
- 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 :
- // RTL <body> scrollbar.
- 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());
- }
- // Gets the entire size of the scrollable document area, even extending outside
- // of the `<html>` and `<body>` rect bounds if horizontally scrollable.
- 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
- };
- }
- // Returns the inner client rect, subtracting scrollbars if present.
- 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);
- }
- // A "clipping ancestor" is an `overflow` element with the characteristic of
- // clipping (or hiding) child elements. This returns all clipping ancestors
- // of the given element up the tree.
- 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;
- // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
- 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) {
- // Drop non-containing blocks.
- result = result.filter(ancestor => ancestor !== currentNode);
- } else {
- // Record last containing block for next iteration.
- currentContainingBlockComputedStyle = computedStyle;
- }
- currentNode = getParentNode(currentNode);
- }
- cache.set(element, result);
- return result;
- }
- // Gets the maximum area that the element is visible in due to any number of
- // clipping ancestors.
- 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) {
- // If the <body> scrollbar appears on the left (e.g. RTL systems). Use
- // Firefox with layout.scrollbar.side = 3 in about:config to test this.
- 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;
- // Firefox returns the <html> element as the offsetParent if it's non-static,
- // while Chrome and Safari return the <body> element. The <body> element must
- // be used to perform the correct calculations even if the <html> element is
- // non-static.
- if (getDocumentElement(element) === rawOffsetParent) {
- rawOffsetParent = rawOffsetParent.ownerDocument.body;
- }
- return rawOffsetParent;
- }
- // Gets the closest ancestor positioned element. Handles some edge cases,
- // such as table ancestors and cross browser bugs.
- 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
- };
- // https://samthor.au/2021/observing-dom/
- 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 {
- left,
- top,
- width,
- height
- } = element.getBoundingClientRect();
- 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) {
- // If the reference is clipped, the ratio is 0. Throttle the refresh
- // to prevent an infinite loop of updates.
- timeoutId = setTimeout(() => {
- refresh(false, 1e-7);
- }, 1000);
- } else {
- refresh(false, ratio);
- }
- }
- isFirstUpdate = false;
- }
- // Older browsers don't support a `document` as the root and will throw an
- // error.
- try {
- io = new IntersectionObserver(handleObserve, {
- ...options,
- // Handle <iframe>s
- root: root.ownerDocument
- });
- } catch (e) {
- io = new IntersectionObserver(handleObserve, options);
- }
- io.observe(element);
- }
- refresh(true);
- return cleanup;
- }
- /**
- * Automatically updates the position of the floating element when necessary.
- * Should only be called when the floating element is mounted on the DOM or
- * visible on the screen.
- * @returns cleanup function that should be invoked when the floating element is
- * removed from the DOM or hidden from the screen.
- * @see https://floating-ui.com/docs/autoUpdate
- */
- 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) {
- // Prevent update loops when using the `size` middleware.
- // https://github.com/floating-ui/floating-ui/issues/1740
- 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 && (nextRefRect.x !== prevRefRect.x || nextRefRect.y !== prevRefRect.y || nextRefRect.width !== prevRefRect.width || nextRefRect.height !== prevRefRect.height)) {
- 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);
- }
- };
- }
- /**
- * Resolves with an object of overflow side offsets that determine how much the
- * element is overflowing a given clipping boundary on each side.
- * - positive = overflowing the boundary by that number of pixels
- * - negative = how many pixels left before it will overflow
- * - 0 = lies flush with the boundary
- * @see https://floating-ui.com/docs/detectOverflow
- */
- const detectOverflow = detectOverflow$1;
- /**
- * Modifies the placement by translating the floating element along the
- * specified axes.
- * A number (shorthand for `mainAxis` or distance), or an axes configuration
- * object may be passed.
- * @see https://floating-ui.com/docs/offset
- */
- const offset = offset$1;
- /**
- * Optimizes the visibility of the floating element by choosing the placement
- * that has the most space available automatically, without needing to specify a
- * preferred placement. Alternative to `flip`.
- * @see https://floating-ui.com/docs/autoPlacement
- */
- const autoPlacement = autoPlacement$1;
- /**
- * Optimizes the visibility of the floating element by shifting it in order to
- * keep it in view when it will overflow the clipping boundary.
- * @see https://floating-ui.com/docs/shift
- */
- const shift = shift$1;
- /**
- * Optimizes the visibility of the floating element by flipping the `placement`
- * in order to keep it in view when the preferred placement(s) will overflow the
- * clipping boundary. Alternative to `autoPlacement`.
- * @see https://floating-ui.com/docs/flip
- */
- const flip = flip$1;
- /**
- * Provides data that allows you to change the size of the floating element —
- * for instance, prevent it from overflowing the clipping boundary or match the
- * width of the reference element.
- * @see https://floating-ui.com/docs/size
- */
- const size = size$1;
- /**
- * Provides data to hide the floating element in applicable situations, such as
- * when it is not in the same clipping context as the reference element.
- * @see https://floating-ui.com/docs/hide
- */
- const hide = hide$1;
- /**
- * Provides data to position an inner element of the floating element so that it
- * appears centered to the reference element.
- * @see https://floating-ui.com/docs/arrow
- */
- const arrow = arrow$1;
- /**
- * Provides improved positioning for inline reference elements that can span
- * over multiple lines, such as hyperlinks or range selections.
- * @see https://floating-ui.com/docs/inline
- */
- const inline = inline$1;
- /**
- * Built-in `limiter` that will stop `shift()` at a certain point.
- */
- const limitShift = limitShift$1;
- /**
- * Computes the `x` and `y` coordinates that will place the floating element
- * next to a given reference element.
- */
- const computePosition = (reference, floating, options) => {
- // This caches the expensive `getClippingElementAncestors` function so that
- // multiple lifecycle resets re-use the same result. It only lives for a
- // single call. If other functions become expensive, we can add them as well.
- 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, getOverflowAncestors, hide, inline, limitShift, offset, platform, shift, size };
|