New source found from dndbeyond.com
This commit is contained in:
+153
-123
@@ -57,97 +57,6 @@ function computeCoordsFromPlacement(_ref, placement, rtl) {
|
||||
return coords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the `x` and `y` coordinates that will place the floating element
|
||||
* next to a given reference element.
|
||||
*
|
||||
* This export does not have any `platform` interface logic. You will need to
|
||||
* write one for the platform you are using Floating UI with.
|
||||
*/
|
||||
const computePosition = async (reference, floating, config) => {
|
||||
const {
|
||||
placement = 'bottom',
|
||||
strategy = 'absolute',
|
||||
middleware = [],
|
||||
platform
|
||||
} = config;
|
||||
const validMiddleware = middleware.filter(Boolean);
|
||||
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
|
||||
let rects = await platform.getElementRects({
|
||||
reference,
|
||||
floating,
|
||||
strategy
|
||||
});
|
||||
let {
|
||||
x,
|
||||
y
|
||||
} = computeCoordsFromPlacement(rects, placement, rtl);
|
||||
let statefulPlacement = placement;
|
||||
let middlewareData = {};
|
||||
let resetCount = 0;
|
||||
for (let i = 0; i < validMiddleware.length; i++) {
|
||||
const {
|
||||
name,
|
||||
fn
|
||||
} = validMiddleware[i];
|
||||
const {
|
||||
x: nextX,
|
||||
y: nextY,
|
||||
data,
|
||||
reset
|
||||
} = await fn({
|
||||
x,
|
||||
y,
|
||||
initialPlacement: placement,
|
||||
placement: statefulPlacement,
|
||||
strategy,
|
||||
middlewareData,
|
||||
rects,
|
||||
platform,
|
||||
elements: {
|
||||
reference,
|
||||
floating
|
||||
}
|
||||
});
|
||||
x = nextX != null ? nextX : x;
|
||||
y = nextY != null ? nextY : y;
|
||||
middlewareData = {
|
||||
...middlewareData,
|
||||
[name]: {
|
||||
...middlewareData[name],
|
||||
...data
|
||||
}
|
||||
};
|
||||
if (reset && resetCount <= 50) {
|
||||
resetCount++;
|
||||
if (typeof reset === 'object') {
|
||||
if (reset.placement) {
|
||||
statefulPlacement = reset.placement;
|
||||
}
|
||||
if (reset.rects) {
|
||||
rects = reset.rects === true ? await platform.getElementRects({
|
||||
reference,
|
||||
floating,
|
||||
strategy
|
||||
}) : reset.rects;
|
||||
}
|
||||
({
|
||||
x,
|
||||
y
|
||||
} = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
|
||||
}
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
placement: statefulPlacement,
|
||||
strategy,
|
||||
middlewareData
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves with an object of overflow side offsets that determine how much the
|
||||
* element is overflowing a given clipping boundary on each side.
|
||||
@@ -213,6 +122,101 @@ async function detectOverflow(state, options) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the `x` and `y` coordinates that will place the floating element
|
||||
* next to a given reference element.
|
||||
*
|
||||
* This export does not have any `platform` interface logic. You will need to
|
||||
* write one for the platform you are using Floating UI with.
|
||||
*/
|
||||
const computePosition = async (reference, floating, config) => {
|
||||
const {
|
||||
placement = 'bottom',
|
||||
strategy = 'absolute',
|
||||
middleware = [],
|
||||
platform
|
||||
} = config;
|
||||
const validMiddleware = middleware.filter(Boolean);
|
||||
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
|
||||
let rects = await platform.getElementRects({
|
||||
reference,
|
||||
floating,
|
||||
strategy
|
||||
});
|
||||
let {
|
||||
x,
|
||||
y
|
||||
} = computeCoordsFromPlacement(rects, placement, rtl);
|
||||
let statefulPlacement = placement;
|
||||
let middlewareData = {};
|
||||
let resetCount = 0;
|
||||
for (let i = 0; i < validMiddleware.length; i++) {
|
||||
var _platform$detectOverf;
|
||||
const {
|
||||
name,
|
||||
fn
|
||||
} = validMiddleware[i];
|
||||
const {
|
||||
x: nextX,
|
||||
y: nextY,
|
||||
data,
|
||||
reset
|
||||
} = await fn({
|
||||
x,
|
||||
y,
|
||||
initialPlacement: placement,
|
||||
placement: statefulPlacement,
|
||||
strategy,
|
||||
middlewareData,
|
||||
rects,
|
||||
platform: {
|
||||
...platform,
|
||||
detectOverflow: (_platform$detectOverf = platform.detectOverflow) != null ? _platform$detectOverf : detectOverflow
|
||||
},
|
||||
elements: {
|
||||
reference,
|
||||
floating
|
||||
}
|
||||
});
|
||||
x = nextX != null ? nextX : x;
|
||||
y = nextY != null ? nextY : y;
|
||||
middlewareData = {
|
||||
...middlewareData,
|
||||
[name]: {
|
||||
...middlewareData[name],
|
||||
...data
|
||||
}
|
||||
};
|
||||
if (reset && resetCount <= 50) {
|
||||
resetCount++;
|
||||
if (typeof reset === 'object') {
|
||||
if (reset.placement) {
|
||||
statefulPlacement = reset.placement;
|
||||
}
|
||||
if (reset.rects) {
|
||||
rects = reset.rects === true ? await platform.getElementRects({
|
||||
reference,
|
||||
floating,
|
||||
strategy
|
||||
}) : reset.rects;
|
||||
}
|
||||
({
|
||||
x,
|
||||
y
|
||||
} = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
|
||||
}
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
placement: statefulPlacement,
|
||||
strategy,
|
||||
middlewareData
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides data to position an inner element of the floating element so that it
|
||||
* appears centered to the reference element.
|
||||
@@ -334,7 +338,7 @@ const autoPlacement = function (options) {
|
||||
...detectOverflowOptions
|
||||
} = evaluate(options, state);
|
||||
const placements$1 = alignment !== undefined || allowedPlacements === placements ? getPlacementList(alignment || null, autoAlignment, allowedPlacements) : allowedPlacements;
|
||||
const overflow = await detectOverflow(state, detectOverflowOptions);
|
||||
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
||||
const currentIndex = ((_middlewareData$autoP = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP.index) || 0;
|
||||
const currentPlacement = placements$1[currentIndex];
|
||||
if (currentPlacement == null) {
|
||||
@@ -439,14 +443,16 @@ const flip = function (options) {
|
||||
return {};
|
||||
}
|
||||
const side = getSide(placement);
|
||||
const initialSideAxis = getSideAxis(initialPlacement);
|
||||
const isBasePlacement = getSide(initialPlacement) === initialPlacement;
|
||||
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
|
||||
const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
|
||||
if (!specifiedFallbackPlacements && fallbackAxisSideDirection !== 'none') {
|
||||
const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== 'none';
|
||||
if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) {
|
||||
fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
|
||||
}
|
||||
const placements = [initialPlacement, ...fallbackPlacements];
|
||||
const overflow = await detectOverflow(state, detectOverflowOptions);
|
||||
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
||||
const overflows = [];
|
||||
let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
|
||||
if (checkMainAxis) {
|
||||
@@ -467,16 +473,22 @@ const flip = function (options) {
|
||||
const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
|
||||
const nextPlacement = placements[nextIndex];
|
||||
if (nextPlacement) {
|
||||
// Try next placement and re-run the lifecycle.
|
||||
return {
|
||||
data: {
|
||||
index: nextIndex,
|
||||
overflows: overflowsData
|
||||
},
|
||||
reset: {
|
||||
placement: nextPlacement
|
||||
}
|
||||
};
|
||||
const ignoreCrossAxisOverflow = checkCrossAxis === 'alignment' ? initialSideAxis !== getSideAxis(nextPlacement) : false;
|
||||
if (!ignoreCrossAxisOverflow ||
|
||||
// We leave the current main axis only if every placement on that axis
|
||||
// overflows the main axis.
|
||||
overflowsData.every(d => getSideAxis(d.placement) === initialSideAxis ? d.overflows[0] > 0 : true)) {
|
||||
// Try next placement and re-run the lifecycle.
|
||||
return {
|
||||
data: {
|
||||
index: nextIndex,
|
||||
overflows: overflowsData
|
||||
},
|
||||
reset: {
|
||||
placement: nextPlacement
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// First, find the candidates that fit on the mainAxis side of overflow,
|
||||
@@ -488,8 +500,17 @@ const flip = function (options) {
|
||||
switch (fallbackStrategy) {
|
||||
case 'bestFit':
|
||||
{
|
||||
var _overflowsData$map$so;
|
||||
const placement = (_overflowsData$map$so = overflowsData.map(d => [d.placement, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$map$so[0];
|
||||
var _overflowsData$filter2;
|
||||
const placement = (_overflowsData$filter2 = overflowsData.filter(d => {
|
||||
if (hasFallbackAxisSideDirection) {
|
||||
const currentSideAxis = getSideAxis(d.placement);
|
||||
return currentSideAxis === initialSideAxis ||
|
||||
// Create a bias to the `y` side axis due to horizontal
|
||||
// reading directions favoring greater width.
|
||||
currentSideAxis === 'y';
|
||||
}
|
||||
return true;
|
||||
}).map(d => [d.placement, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];
|
||||
if (placement) {
|
||||
resetPlacement = placement;
|
||||
}
|
||||
@@ -538,7 +559,8 @@ const hide = function (options) {
|
||||
options,
|
||||
async fn(state) {
|
||||
const {
|
||||
rects
|
||||
rects,
|
||||
platform
|
||||
} = state;
|
||||
const {
|
||||
strategy = 'referenceHidden',
|
||||
@@ -547,7 +569,7 @@ const hide = function (options) {
|
||||
switch (strategy) {
|
||||
case 'referenceHidden':
|
||||
{
|
||||
const overflow = await detectOverflow(state, {
|
||||
const overflow = await platform.detectOverflow(state, {
|
||||
...detectOverflowOptions,
|
||||
elementContext: 'reference'
|
||||
});
|
||||
@@ -561,7 +583,7 @@ const hide = function (options) {
|
||||
}
|
||||
case 'escaped':
|
||||
{
|
||||
const overflow = await detectOverflow(state, {
|
||||
const overflow = await platform.detectOverflow(state, {
|
||||
...detectOverflowOptions,
|
||||
altBoundary: true
|
||||
});
|
||||
@@ -713,6 +735,8 @@ const inline = function (options) {
|
||||
};
|
||||
};
|
||||
|
||||
const originSides = /*#__PURE__*/new Set(['left', 'top']);
|
||||
|
||||
// For type backwards-compatibility, the `OffsetOptions` type was also
|
||||
// Derivable.
|
||||
|
||||
@@ -726,7 +750,7 @@ async function convertValueToCoords(state, options) {
|
||||
const side = getSide(placement);
|
||||
const alignment = getAlignment(placement);
|
||||
const isVertical = getSideAxis(placement) === 'y';
|
||||
const mainAxisMulti = ['left', 'top'].includes(side) ? -1 : 1;
|
||||
const mainAxisMulti = originSides.has(side) ? -1 : 1;
|
||||
const crossAxisMulti = rtl && isVertical ? -1 : 1;
|
||||
const rawValue = evaluate(options, state);
|
||||
|
||||
@@ -740,10 +764,9 @@ async function convertValueToCoords(state, options) {
|
||||
crossAxis: 0,
|
||||
alignmentAxis: null
|
||||
} : {
|
||||
mainAxis: 0,
|
||||
crossAxis: 0,
|
||||
alignmentAxis: null,
|
||||
...rawValue
|
||||
mainAxis: rawValue.mainAxis || 0,
|
||||
crossAxis: rawValue.crossAxis || 0,
|
||||
alignmentAxis: rawValue.alignmentAxis
|
||||
};
|
||||
if (alignment && typeof alignmentAxis === 'number') {
|
||||
crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis;
|
||||
@@ -814,7 +837,8 @@ const shift = function (options) {
|
||||
const {
|
||||
x,
|
||||
y,
|
||||
placement
|
||||
placement,
|
||||
platform
|
||||
} = state;
|
||||
const {
|
||||
mainAxis: checkMainAxis = true,
|
||||
@@ -837,7 +861,7 @@ const shift = function (options) {
|
||||
x,
|
||||
y
|
||||
};
|
||||
const overflow = await detectOverflow(state, detectOverflowOptions);
|
||||
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
||||
const crossAxis = getSideAxis(getSide(placement));
|
||||
const mainAxis = getOppositeAxis(crossAxis);
|
||||
let mainAxisCoord = coords[mainAxis];
|
||||
@@ -865,7 +889,11 @@ const shift = function (options) {
|
||||
...limitedCoords,
|
||||
data: {
|
||||
x: limitedCoords.x - x,
|
||||
y: limitedCoords.y - y
|
||||
y: limitedCoords.y - y,
|
||||
enabled: {
|
||||
[mainAxis]: checkMainAxis,
|
||||
[crossAxis]: checkCrossAxis
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -923,7 +951,7 @@ const limitShift = function (options) {
|
||||
if (checkCrossAxis) {
|
||||
var _middlewareData$offse, _middlewareData$offse2;
|
||||
const len = mainAxis === 'y' ? 'width' : 'height';
|
||||
const isOriginSide = ['top', 'left'].includes(getSide(placement));
|
||||
const isOriginSide = originSides.has(getSide(placement));
|
||||
const limitMin = rects.reference[crossAxis] - rects.floating[len] + (isOriginSide ? ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse[crossAxis]) || 0 : 0) + (isOriginSide ? 0 : computedOffset.crossAxis);
|
||||
const limitMax = rects.reference[crossAxis] + rects.reference[len] + (isOriginSide ? 0 : ((_middlewareData$offse2 = middlewareData.offset) == null ? void 0 : _middlewareData$offse2[crossAxis]) || 0) - (isOriginSide ? computedOffset.crossAxis : 0);
|
||||
if (crossAxisCoord < limitMin) {
|
||||
@@ -954,6 +982,7 @@ const size = function (options) {
|
||||
name: 'size',
|
||||
options,
|
||||
async fn(state) {
|
||||
var _state$middlewareData, _state$middlewareData2;
|
||||
const {
|
||||
placement,
|
||||
rects,
|
||||
@@ -964,7 +993,7 @@ const size = function (options) {
|
||||
apply = () => {},
|
||||
...detectOverflowOptions
|
||||
} = evaluate(options, state);
|
||||
const overflow = await detectOverflow(state, detectOverflowOptions);
|
||||
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
||||
const side = getSide(placement);
|
||||
const alignment = getAlignment(placement);
|
||||
const isYAxis = getSideAxis(placement) === 'y';
|
||||
@@ -988,10 +1017,11 @@ const size = function (options) {
|
||||
const noShift = !state.middlewareData.shift;
|
||||
let availableHeight = overflowAvailableHeight;
|
||||
let availableWidth = overflowAvailableWidth;
|
||||
if (isYAxis) {
|
||||
availableWidth = alignment || noShift ? min(overflowAvailableWidth, maximumClippingWidth) : maximumClippingWidth;
|
||||
} else {
|
||||
availableHeight = alignment || noShift ? min(overflowAvailableHeight, maximumClippingHeight) : maximumClippingHeight;
|
||||
if ((_state$middlewareData = state.middlewareData.shift) != null && _state$middlewareData.enabled.x) {
|
||||
availableWidth = maximumClippingWidth;
|
||||
}
|
||||
if ((_state$middlewareData2 = state.middlewareData.shift) != null && _state$middlewareData2.enabled.y) {
|
||||
availableHeight = maximumClippingHeight;
|
||||
}
|
||||
if (noShift && !alignment) {
|
||||
const xMin = max(overflow.left, 0);
|
||||
|
||||
+102
-40
@@ -1,10 +1,10 @@
|
||||
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 { rectToClientRect, arrow as arrow$1, autoPlacement as autoPlacement$1, detectOverflow as detectOverflow$1, flip as flip$1, hide as hide$1, inline as inline$1, limitShift as limitShift$1, offset as offset$1, shift as shift$1, size as size$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, getDocumentElement, getNodeName, isOverflowElement, getNodeScroll, getOverflowAncestors, getParentNode, isLastTraversableNode, isContainingBlock, isTableElement, getContainingBlock } from '@floating-ui/utils/dom';
|
||||
import { getComputedStyle as getComputedStyle$1, 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);
|
||||
const css = getComputedStyle$1(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;
|
||||
@@ -105,11 +105,11 @@ function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetPar
|
||||
const win = getWindow(domElement);
|
||||
const offsetWin = offsetParent && isElement(offsetParent) ? getWindow(offsetParent) : offsetParent;
|
||||
let currentWin = win;
|
||||
let currentIFrame = currentWin.frameElement;
|
||||
let currentIFrame = getFrameElement(currentWin);
|
||||
while (currentIFrame && offsetParent && offsetWin !== currentWin) {
|
||||
const iframeScale = getScale(currentIFrame);
|
||||
const iframeRect = currentIFrame.getBoundingClientRect();
|
||||
const css = getComputedStyle(currentIFrame);
|
||||
const css = getComputedStyle$1(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;
|
||||
@@ -119,7 +119,7 @@ function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetPar
|
||||
x += left;
|
||||
y += top;
|
||||
currentWin = getWindow(currentIFrame);
|
||||
currentIFrame = currentWin.frameElement;
|
||||
currentIFrame = getFrameElement(currentWin);
|
||||
}
|
||||
}
|
||||
return rectToClientRect({
|
||||
@@ -130,15 +130,24 @@ function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetPar
|
||||
});
|
||||
}
|
||||
|
||||
const topLayerSelectors = [':popover-open', ':modal'];
|
||||
function isTopLayer(element) {
|
||||
return topLayerSelectors.some(selector => {
|
||||
try {
|
||||
return element.matches(selector);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// 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) {
|
||||
const htmlRect = documentElement.getBoundingClientRect();
|
||||
const x = htmlRect.left + scroll.scrollLeft - getWindowScrollBarX(documentElement, htmlRect);
|
||||
const y = htmlRect.top + scroll.scrollTop;
|
||||
return {
|
||||
x,
|
||||
y
|
||||
};
|
||||
}
|
||||
|
||||
function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
|
||||
@@ -172,11 +181,12 @@ function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
|
||||
offsets.y = offsetRect.y + offsetParent.clientTop;
|
||||
}
|
||||
}
|
||||
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
|
||||
return {
|
||||
width: rect.width * scale.x,
|
||||
height: rect.height * scale.y,
|
||||
x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x,
|
||||
y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -184,12 +194,6 @@ function getClientRects(element) {
|
||||
return Array.from(element.getClientRects());
|
||||
}
|
||||
|
||||
function getWindowScrollBarX(element) {
|
||||
// If <html> has a CSS width greater than the viewport, then this will be
|
||||
// incorrect for RTL.
|
||||
return getBoundingClientRect(getDocumentElement(element)).left + getNodeScroll(element).scrollLeft;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -200,7 +204,7 @@ function getDocumentRect(element) {
|
||||
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') {
|
||||
if (getComputedStyle$1(body).direction === 'rtl') {
|
||||
x += max(html.clientWidth, body.clientWidth) - width;
|
||||
}
|
||||
return {
|
||||
@@ -211,6 +215,10 @@ function getDocumentRect(element) {
|
||||
};
|
||||
}
|
||||
|
||||
// Safety check: ensure the scrollbar space is reasonable in case this
|
||||
// calculation is affected by unusual styles.
|
||||
// Most scrollbars leave 15-18px of space.
|
||||
const SCROLLBAR_MAX = 25;
|
||||
function getViewportRect(element, strategy) {
|
||||
const win = getWindow(element);
|
||||
const html = getDocumentElement(element);
|
||||
@@ -228,6 +236,24 @@ function getViewportRect(element, strategy) {
|
||||
y = visualViewport.offsetTop;
|
||||
}
|
||||
}
|
||||
const windowScrollbarX = getWindowScrollBarX(html);
|
||||
// <html> `overflow: hidden` + `scrollbar-gutter: stable` reduces the
|
||||
// visual width of the <html> but this is not considered in the size
|
||||
// of `html.clientWidth`.
|
||||
if (windowScrollbarX <= 0) {
|
||||
const doc = html.ownerDocument;
|
||||
const body = doc.body;
|
||||
const bodyStyles = getComputedStyle(body);
|
||||
const bodyMarginInline = doc.compatMode === 'CSS1Compat' ? parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight) || 0 : 0;
|
||||
const clippingStableScrollbarWidth = Math.abs(html.clientWidth - body.clientWidth - bodyMarginInline);
|
||||
if (clippingStableScrollbarWidth <= SCROLLBAR_MAX) {
|
||||
width -= clippingStableScrollbarWidth;
|
||||
}
|
||||
} else if (windowScrollbarX <= SCROLLBAR_MAX) {
|
||||
// If the <body> scrollbar is on the left, the width needs to be extended
|
||||
// by the scrollbar amount so there isn't extra space on the right.
|
||||
width += windowScrollbarX;
|
||||
}
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
@@ -236,6 +262,7 @@ function getViewportRect(element, strategy) {
|
||||
};
|
||||
}
|
||||
|
||||
const absoluteOrFixed = /*#__PURE__*/new Set(['absolute', 'fixed']);
|
||||
// Returns the inner client rect, subtracting scrollbars if present.
|
||||
function getInnerBoundingClientRect(element, strategy) {
|
||||
const clientRect = getBoundingClientRect(element, true, strategy === 'fixed');
|
||||
@@ -264,9 +291,10 @@ function getClientRectFromClippingAncestor(element, clippingAncestor, strategy)
|
||||
} else {
|
||||
const visualOffsets = getVisualOffsets(element);
|
||||
rect = {
|
||||
...clippingAncestor,
|
||||
x: clippingAncestor.x - visualOffsets.x,
|
||||
y: clippingAncestor.y - visualOffsets.y
|
||||
y: clippingAncestor.y - visualOffsets.y,
|
||||
width: clippingAncestor.width,
|
||||
height: clippingAncestor.height
|
||||
};
|
||||
}
|
||||
return rectToClientRect(rect);
|
||||
@@ -276,7 +304,7 @@ function hasFixedPositionAncestor(element, stopNode) {
|
||||
if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) {
|
||||
return false;
|
||||
}
|
||||
return getComputedStyle(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode);
|
||||
return getComputedStyle$1(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode);
|
||||
}
|
||||
|
||||
// A "clipping ancestor" is an `overflow` element with the characteristic of
|
||||
@@ -289,17 +317,17 @@ function getClippingElementAncestors(element, cache) {
|
||||
}
|
||||
let result = getOverflowAncestors(element, [], false).filter(el => isElement(el) && getNodeName(el) !== 'body');
|
||||
let currentContainingBlockComputedStyle = null;
|
||||
const elementIsFixed = getComputedStyle(element).position === 'fixed';
|
||||
const elementIsFixed = getComputedStyle$1(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 computedStyle = getComputedStyle$1(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);
|
||||
const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === 'static' && !!currentContainingBlockComputedStyle && absoluteOrFixed.has(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode);
|
||||
if (shouldDropCurrentNode) {
|
||||
// Drop non-containing blocks.
|
||||
result = result.filter(ancestor => ancestor !== currentNode);
|
||||
@@ -362,6 +390,12 @@ function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
|
||||
scrollTop: 0
|
||||
};
|
||||
const offsets = createCoords(0);
|
||||
|
||||
// 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.
|
||||
function setLeftRTLScrollbarOffset() {
|
||||
offsets.x = getWindowScrollBarX(documentElement);
|
||||
}
|
||||
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
|
||||
if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {
|
||||
scroll = getNodeScroll(offsetParent);
|
||||
@@ -371,11 +405,15 @@ function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
|
||||
offsets.x = offsetRect.x + offsetParent.clientLeft;
|
||||
offsets.y = offsetRect.y + offsetParent.clientTop;
|
||||
} else if (documentElement) {
|
||||
offsets.x = getWindowScrollBarX(documentElement);
|
||||
setLeftRTLScrollbarOffset();
|
||||
}
|
||||
}
|
||||
const x = rect.left + scroll.scrollLeft - offsets.x;
|
||||
const y = rect.top + scroll.scrollTop - offsets.y;
|
||||
if (isFixed && !isOffsetParentAnElement && documentElement) {
|
||||
setLeftRTLScrollbarOffset();
|
||||
}
|
||||
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,
|
||||
@@ -385,17 +423,26 @@ function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
|
||||
}
|
||||
|
||||
function isStaticPositioned(element) {
|
||||
return getComputedStyle(element).position === 'static';
|
||||
return getComputedStyle$1(element).position === 'static';
|
||||
}
|
||||
|
||||
function getTrueOffsetParent(element, polyfill) {
|
||||
if (!isHTMLElement(element) || getComputedStyle(element).position === 'fixed') {
|
||||
if (!isHTMLElement(element) || getComputedStyle$1(element).position === 'fixed') {
|
||||
return null;
|
||||
}
|
||||
if (polyfill) {
|
||||
return polyfill(element);
|
||||
}
|
||||
return element.offsetParent;
|
||||
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,
|
||||
@@ -441,7 +488,7 @@ const getElementRects = async function (data) {
|
||||
};
|
||||
|
||||
function isRTL(element) {
|
||||
return getComputedStyle(element).direction === 'rtl';
|
||||
return getComputedStyle$1(element).direction === 'rtl';
|
||||
}
|
||||
|
||||
const platform = {
|
||||
@@ -457,6 +504,10 @@ const platform = {
|
||||
isRTL
|
||||
};
|
||||
|
||||
function rectsAreEqual(a, b) {
|
||||
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
||||
}
|
||||
|
||||
// https://samthor.au/2021/observing-dom/
|
||||
function observeMove(element, onMove) {
|
||||
let io = null;
|
||||
@@ -476,12 +527,13 @@ function observeMove(element, onMove) {
|
||||
threshold = 1;
|
||||
}
|
||||
cleanup();
|
||||
const elementRectForRootMargin = element.getBoundingClientRect();
|
||||
const {
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height
|
||||
} = element.getBoundingClientRect();
|
||||
} = elementRectForRootMargin;
|
||||
if (!skip) {
|
||||
onMove();
|
||||
}
|
||||
@@ -514,6 +566,16 @@ function observeMove(element, onMove) {
|
||||
refresh(false, ratio);
|
||||
}
|
||||
}
|
||||
if (ratio === 1 && !rectsAreEqual(elementRectForRootMargin, element.getBoundingClientRect())) {
|
||||
// It's possible that even though the ratio is reported as 1, the
|
||||
// element is not actually fully within the IntersectionObserver's root
|
||||
// area anymore. This can happen under performance constraints. This may
|
||||
// be a bug in the browser's IntersectionObserver implementation. To
|
||||
// work around this, we compare the element's bounding rect now with
|
||||
// what it was at the time we created the IntersectionObserver. If they
|
||||
// are not equal then the element moved, so we refresh.
|
||||
refresh();
|
||||
}
|
||||
isFirstUpdate = false;
|
||||
}
|
||||
|
||||
@@ -525,7 +587,7 @@ function observeMove(element, onMove) {
|
||||
// Handle <iframe>s
|
||||
root: root.ownerDocument
|
||||
});
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
io = new IntersectionObserver(handleObserve, options);
|
||||
}
|
||||
io.observe(element);
|
||||
@@ -591,7 +653,7 @@ function autoUpdate(reference, floating, update, options) {
|
||||
}
|
||||
function frameLoop() {
|
||||
const nextRefRect = getBoundingClientRect(reference);
|
||||
if (prevRefRect && (nextRefRect.x !== prevRefRect.x || nextRefRect.y !== prevRefRect.y || nextRefRect.width !== prevRefRect.width || nextRefRect.height !== prevRefRect.height)) {
|
||||
if (prevRefRect && !rectsAreEqual(prevRefRect, nextRefRect)) {
|
||||
update();
|
||||
}
|
||||
prevRefRect = nextRefRect;
|
||||
|
||||
+371
@@ -0,0 +1,371 @@
|
||||
import { computePosition, arrow as arrow$2, autoPlacement as autoPlacement$1, flip as flip$1, hide as hide$1, inline as inline$1, limitShift as limitShift$1, offset as offset$1, shift as shift$1, size as size$1 } from '@floating-ui/dom';
|
||||
export { autoUpdate, computePosition, detectOverflow, getOverflowAncestors, platform } from '@floating-ui/dom';
|
||||
import * as React from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
|
||||
var isClient = typeof document !== 'undefined';
|
||||
|
||||
var noop = function noop() {};
|
||||
var index = isClient ? useLayoutEffect : noop;
|
||||
|
||||
// Fork of `fast-deep-equal` that only does the comparisons we need and compares
|
||||
// functions
|
||||
function deepEqual(a, b) {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
if (typeof a !== typeof b) {
|
||||
return false;
|
||||
}
|
||||
if (typeof a === 'function' && a.toString() === b.toString()) {
|
||||
return true;
|
||||
}
|
||||
let length;
|
||||
let i;
|
||||
let keys;
|
||||
if (a && b && typeof a === 'object') {
|
||||
if (Array.isArray(a)) {
|
||||
length = a.length;
|
||||
if (length !== b.length) return false;
|
||||
for (i = length; i-- !== 0;) {
|
||||
if (!deepEqual(a[i], b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
keys = Object.keys(a);
|
||||
length = keys.length;
|
||||
if (length !== Object.keys(b).length) {
|
||||
return false;
|
||||
}
|
||||
for (i = length; i-- !== 0;) {
|
||||
if (!{}.hasOwnProperty.call(b, keys[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (i = length; i-- !== 0;) {
|
||||
const key = keys[i];
|
||||
if (key === '_owner' && a.$$typeof) {
|
||||
continue;
|
||||
}
|
||||
if (!deepEqual(a[key], b[key])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return a !== a && b !== b;
|
||||
}
|
||||
|
||||
function getDPR(element) {
|
||||
if (typeof window === 'undefined') {
|
||||
return 1;
|
||||
}
|
||||
const win = element.ownerDocument.defaultView || window;
|
||||
return win.devicePixelRatio || 1;
|
||||
}
|
||||
|
||||
function roundByDPR(element, value) {
|
||||
const dpr = getDPR(element);
|
||||
return Math.round(value * dpr) / dpr;
|
||||
}
|
||||
|
||||
function useLatestRef(value) {
|
||||
const ref = React.useRef(value);
|
||||
index(() => {
|
||||
ref.current = value;
|
||||
});
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to position a floating element.
|
||||
* @see https://floating-ui.com/docs/useFloating
|
||||
*/
|
||||
function useFloating(options) {
|
||||
if (options === void 0) {
|
||||
options = {};
|
||||
}
|
||||
const {
|
||||
placement = 'bottom',
|
||||
strategy = 'absolute',
|
||||
middleware = [],
|
||||
platform,
|
||||
elements: {
|
||||
reference: externalReference,
|
||||
floating: externalFloating
|
||||
} = {},
|
||||
transform = true,
|
||||
whileElementsMounted,
|
||||
open
|
||||
} = options;
|
||||
const [data, setData] = React.useState({
|
||||
x: 0,
|
||||
y: 0,
|
||||
strategy,
|
||||
placement,
|
||||
middlewareData: {},
|
||||
isPositioned: false
|
||||
});
|
||||
const [latestMiddleware, setLatestMiddleware] = React.useState(middleware);
|
||||
if (!deepEqual(latestMiddleware, middleware)) {
|
||||
setLatestMiddleware(middleware);
|
||||
}
|
||||
const [_reference, _setReference] = React.useState(null);
|
||||
const [_floating, _setFloating] = React.useState(null);
|
||||
const setReference = React.useCallback(node => {
|
||||
if (node !== referenceRef.current) {
|
||||
referenceRef.current = node;
|
||||
_setReference(node);
|
||||
}
|
||||
}, []);
|
||||
const setFloating = React.useCallback(node => {
|
||||
if (node !== floatingRef.current) {
|
||||
floatingRef.current = node;
|
||||
_setFloating(node);
|
||||
}
|
||||
}, []);
|
||||
const referenceEl = externalReference || _reference;
|
||||
const floatingEl = externalFloating || _floating;
|
||||
const referenceRef = React.useRef(null);
|
||||
const floatingRef = React.useRef(null);
|
||||
const dataRef = React.useRef(data);
|
||||
const hasWhileElementsMounted = whileElementsMounted != null;
|
||||
const whileElementsMountedRef = useLatestRef(whileElementsMounted);
|
||||
const platformRef = useLatestRef(platform);
|
||||
const openRef = useLatestRef(open);
|
||||
const update = React.useCallback(() => {
|
||||
if (!referenceRef.current || !floatingRef.current) {
|
||||
return;
|
||||
}
|
||||
const config = {
|
||||
placement,
|
||||
strategy,
|
||||
middleware: latestMiddleware
|
||||
};
|
||||
if (platformRef.current) {
|
||||
config.platform = platformRef.current;
|
||||
}
|
||||
computePosition(referenceRef.current, floatingRef.current, config).then(data => {
|
||||
const fullData = {
|
||||
...data,
|
||||
// The floating element's position may be recomputed while it's closed
|
||||
// but still mounted (such as when transitioning out). To ensure
|
||||
// `isPositioned` will be `false` initially on the next open, avoid
|
||||
// setting it to `true` when `open === false` (must be specified).
|
||||
isPositioned: openRef.current !== false
|
||||
};
|
||||
if (isMountedRef.current && !deepEqual(dataRef.current, fullData)) {
|
||||
dataRef.current = fullData;
|
||||
ReactDOM.flushSync(() => {
|
||||
setData(fullData);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [latestMiddleware, placement, strategy, platformRef, openRef]);
|
||||
index(() => {
|
||||
if (open === false && dataRef.current.isPositioned) {
|
||||
dataRef.current.isPositioned = false;
|
||||
setData(data => ({
|
||||
...data,
|
||||
isPositioned: false
|
||||
}));
|
||||
}
|
||||
}, [open]);
|
||||
const isMountedRef = React.useRef(false);
|
||||
index(() => {
|
||||
isMountedRef.current = true;
|
||||
return () => {
|
||||
isMountedRef.current = false;
|
||||
};
|
||||
}, []);
|
||||
index(() => {
|
||||
if (referenceEl) referenceRef.current = referenceEl;
|
||||
if (floatingEl) floatingRef.current = floatingEl;
|
||||
if (referenceEl && floatingEl) {
|
||||
if (whileElementsMountedRef.current) {
|
||||
return whileElementsMountedRef.current(referenceEl, floatingEl, update);
|
||||
}
|
||||
update();
|
||||
}
|
||||
}, [referenceEl, floatingEl, update, whileElementsMountedRef, hasWhileElementsMounted]);
|
||||
const refs = React.useMemo(() => ({
|
||||
reference: referenceRef,
|
||||
floating: floatingRef,
|
||||
setReference,
|
||||
setFloating
|
||||
}), [setReference, setFloating]);
|
||||
const elements = React.useMemo(() => ({
|
||||
reference: referenceEl,
|
||||
floating: floatingEl
|
||||
}), [referenceEl, floatingEl]);
|
||||
const floatingStyles = React.useMemo(() => {
|
||||
const initialStyles = {
|
||||
position: strategy,
|
||||
left: 0,
|
||||
top: 0
|
||||
};
|
||||
if (!elements.floating) {
|
||||
return initialStyles;
|
||||
}
|
||||
const x = roundByDPR(elements.floating, data.x);
|
||||
const y = roundByDPR(elements.floating, data.y);
|
||||
if (transform) {
|
||||
return {
|
||||
...initialStyles,
|
||||
transform: "translate(" + x + "px, " + y + "px)",
|
||||
...(getDPR(elements.floating) >= 1.5 && {
|
||||
willChange: 'transform'
|
||||
})
|
||||
};
|
||||
}
|
||||
return {
|
||||
position: strategy,
|
||||
left: x,
|
||||
top: y
|
||||
};
|
||||
}, [strategy, transform, elements.floating, data.x, data.y]);
|
||||
return React.useMemo(() => ({
|
||||
...data,
|
||||
update,
|
||||
refs,
|
||||
elements,
|
||||
floatingStyles
|
||||
}), [data, update, refs, elements, floatingStyles]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to position an inner element of the floating element so that it
|
||||
* appears centered to the reference element.
|
||||
* This wraps the core `arrow` middleware to allow React refs as the element.
|
||||
* @see https://floating-ui.com/docs/arrow
|
||||
*/
|
||||
const arrow$1 = options => {
|
||||
function isRef(value) {
|
||||
return {}.hasOwnProperty.call(value, 'current');
|
||||
}
|
||||
return {
|
||||
name: 'arrow',
|
||||
options,
|
||||
fn(state) {
|
||||
const {
|
||||
element,
|
||||
padding
|
||||
} = typeof options === 'function' ? options(state) : options;
|
||||
if (element && isRef(element)) {
|
||||
if (element.current != null) {
|
||||
return arrow$2({
|
||||
element: element.current,
|
||||
padding
|
||||
}).fn(state);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
if (element) {
|
||||
return arrow$2({
|
||||
element,
|
||||
padding
|
||||
}).fn(state);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 = (options, deps) => ({
|
||||
...offset$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 = (options, deps) => ({
|
||||
...shift$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* Built-in `limiter` that will stop `shift()` at a certain point.
|
||||
*/
|
||||
const limitShift = (options, deps) => ({
|
||||
...limitShift$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 = (options, deps) => ({
|
||||
...flip$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 = (options, deps) => ({
|
||||
...size$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 = (options, deps) => ({
|
||||
...autoPlacement$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 = (options, deps) => ({
|
||||
...hide$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 = (options, deps) => ({
|
||||
...inline$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
/**
|
||||
* Provides data to position an inner element of the floating element so that it
|
||||
* appears centered to the reference element.
|
||||
* This wraps the core `arrow` middleware to allow React refs as the element.
|
||||
* @see https://floating-ui.com/docs/arrow
|
||||
*/
|
||||
const arrow = (options, deps) => ({
|
||||
...arrow$1(options),
|
||||
options: [options, deps]
|
||||
});
|
||||
|
||||
export { arrow, autoPlacement, flip, hide, inline, limitShift, offset, shift, size, useFloating };
|
||||
+4595
File diff suppressed because it is too large
Load Diff
+537
@@ -0,0 +1,537 @@
|
||||
import { isShadowRoot, isHTMLElement } from '@floating-ui/utils/dom';
|
||||
import * as React from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
import { floor } from '@floating-ui/utils';
|
||||
import { tabbable } from 'tabbable';
|
||||
|
||||
// Avoid Chrome DevTools blue warning.
|
||||
function getPlatform() {
|
||||
const uaData = navigator.userAgentData;
|
||||
if (uaData != null && uaData.platform) {
|
||||
return uaData.platform;
|
||||
}
|
||||
return navigator.platform;
|
||||
}
|
||||
function getUserAgent() {
|
||||
const uaData = navigator.userAgentData;
|
||||
if (uaData && Array.isArray(uaData.brands)) {
|
||||
return uaData.brands.map(_ref => {
|
||||
let {
|
||||
brand,
|
||||
version
|
||||
} = _ref;
|
||||
return brand + "/" + version;
|
||||
}).join(' ');
|
||||
}
|
||||
return navigator.userAgent;
|
||||
}
|
||||
function isSafari() {
|
||||
// Chrome DevTools does not complain about navigator.vendor
|
||||
return /apple/i.test(navigator.vendor);
|
||||
}
|
||||
function isAndroid() {
|
||||
const re = /android/i;
|
||||
return re.test(getPlatform()) || re.test(getUserAgent());
|
||||
}
|
||||
function isMac() {
|
||||
return getPlatform().toLowerCase().startsWith('mac') && !navigator.maxTouchPoints;
|
||||
}
|
||||
function isJSDOM() {
|
||||
return getUserAgent().includes('jsdom/');
|
||||
}
|
||||
|
||||
const FOCUSABLE_ATTRIBUTE = 'data-floating-ui-focusable';
|
||||
const TYPEABLE_SELECTOR = "input:not([type='hidden']):not([disabled])," + "[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";
|
||||
const ARROW_LEFT = 'ArrowLeft';
|
||||
const ARROW_RIGHT = 'ArrowRight';
|
||||
const ARROW_UP = 'ArrowUp';
|
||||
const ARROW_DOWN = 'ArrowDown';
|
||||
|
||||
function activeElement(doc) {
|
||||
let activeElement = doc.activeElement;
|
||||
while (((_activeElement = activeElement) == null || (_activeElement = _activeElement.shadowRoot) == null ? void 0 : _activeElement.activeElement) != null) {
|
||||
var _activeElement;
|
||||
activeElement = activeElement.shadowRoot.activeElement;
|
||||
}
|
||||
return activeElement;
|
||||
}
|
||||
function contains(parent, child) {
|
||||
if (!parent || !child) {
|
||||
return false;
|
||||
}
|
||||
const rootNode = child.getRootNode == null ? void 0 : child.getRootNode();
|
||||
|
||||
// First, attempt with faster native method
|
||||
if (parent.contains(child)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// then fallback to custom implementation with Shadow DOM support
|
||||
if (rootNode && isShadowRoot(rootNode)) {
|
||||
let next = child;
|
||||
while (next) {
|
||||
if (parent === next) {
|
||||
return true;
|
||||
}
|
||||
// @ts-ignore
|
||||
next = next.parentNode || next.host;
|
||||
}
|
||||
}
|
||||
|
||||
// Give up, the result is false
|
||||
return false;
|
||||
}
|
||||
function getTarget(event) {
|
||||
if ('composedPath' in event) {
|
||||
return event.composedPath()[0];
|
||||
}
|
||||
|
||||
// TS thinks `event` is of type never as it assumes all browsers support
|
||||
// `composedPath()`, but browsers without shadow DOM don't.
|
||||
return event.target;
|
||||
}
|
||||
function isEventTargetWithin(event, node) {
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
if ('composedPath' in event) {
|
||||
return event.composedPath().includes(node);
|
||||
}
|
||||
|
||||
// TS thinks `event` is of type never as it assumes all browsers support composedPath, but browsers without shadow dom don't
|
||||
const e = event;
|
||||
return e.target != null && node.contains(e.target);
|
||||
}
|
||||
function isRootElement(element) {
|
||||
return element.matches('html,body');
|
||||
}
|
||||
function getDocument(node) {
|
||||
return (node == null ? void 0 : node.ownerDocument) || document;
|
||||
}
|
||||
function isTypeableElement(element) {
|
||||
return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);
|
||||
}
|
||||
function isTypeableCombobox(element) {
|
||||
if (!element) return false;
|
||||
return element.getAttribute('role') === 'combobox' && isTypeableElement(element);
|
||||
}
|
||||
function matchesFocusVisible(element) {
|
||||
// We don't want to block focus from working with `visibleOnly`
|
||||
// (JSDOM doesn't match `:focus-visible` when the element has `:focus`)
|
||||
if (!element || isJSDOM()) return true;
|
||||
try {
|
||||
return element.matches(':focus-visible');
|
||||
} catch (_e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function getFloatingFocusElement(floatingElement) {
|
||||
if (!floatingElement) {
|
||||
return null;
|
||||
}
|
||||
// Try to find the element that has `{...getFloatingProps()}` spread on it.
|
||||
// This indicates the floating element is acting as a positioning wrapper, and
|
||||
// so focus should be managed on the child element with the event handlers and
|
||||
// aria props.
|
||||
return floatingElement.hasAttribute(FOCUSABLE_ATTRIBUTE) ? floatingElement : floatingElement.querySelector("[" + FOCUSABLE_ATTRIBUTE + "]") || floatingElement;
|
||||
}
|
||||
|
||||
function getNodeChildren(nodes, id, onlyOpenChildren) {
|
||||
if (onlyOpenChildren === void 0) {
|
||||
onlyOpenChildren = true;
|
||||
}
|
||||
const directChildren = nodes.filter(node => {
|
||||
var _node$context;
|
||||
return node.parentId === id && (!onlyOpenChildren || ((_node$context = node.context) == null ? void 0 : _node$context.open));
|
||||
});
|
||||
return directChildren.flatMap(child => [child, ...getNodeChildren(nodes, child.id, onlyOpenChildren)]);
|
||||
}
|
||||
function getDeepestNode(nodes, id) {
|
||||
let deepestNodeId;
|
||||
let maxDepth = -1;
|
||||
function findDeepest(nodeId, depth) {
|
||||
if (depth > maxDepth) {
|
||||
deepestNodeId = nodeId;
|
||||
maxDepth = depth;
|
||||
}
|
||||
const children = getNodeChildren(nodes, nodeId);
|
||||
children.forEach(child => {
|
||||
findDeepest(child.id, depth + 1);
|
||||
});
|
||||
}
|
||||
findDeepest(id, 0);
|
||||
return nodes.find(node => node.id === deepestNodeId);
|
||||
}
|
||||
function getNodeAncestors(nodes, id) {
|
||||
var _nodes$find;
|
||||
let allAncestors = [];
|
||||
let currentParentId = (_nodes$find = nodes.find(node => node.id === id)) == null ? void 0 : _nodes$find.parentId;
|
||||
while (currentParentId) {
|
||||
const currentNode = nodes.find(node => node.id === currentParentId);
|
||||
currentParentId = currentNode == null ? void 0 : currentNode.parentId;
|
||||
if (currentNode) {
|
||||
allAncestors = allAncestors.concat(currentNode);
|
||||
}
|
||||
}
|
||||
return allAncestors;
|
||||
}
|
||||
|
||||
function stopEvent(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
function isReactEvent(event) {
|
||||
return 'nativeEvent' in event;
|
||||
}
|
||||
|
||||
// License: https://github.com/adobe/react-spectrum/blob/b35d5c02fe900badccd0cf1a8f23bb593419f238/packages/@react-aria/utils/src/isVirtualEvent.ts
|
||||
function isVirtualClick(event) {
|
||||
// FIXME: Firefox is now emitting a deprecation warning for `mozInputSource`.
|
||||
// Try to find a workaround for this. `react-aria` source still has the check.
|
||||
if (event.mozInputSource === 0 && event.isTrusted) {
|
||||
return true;
|
||||
}
|
||||
if (isAndroid() && event.pointerType) {
|
||||
return event.type === 'click' && event.buttons === 1;
|
||||
}
|
||||
return event.detail === 0 && !event.pointerType;
|
||||
}
|
||||
function isVirtualPointerEvent(event) {
|
||||
if (isJSDOM()) return false;
|
||||
return !isAndroid() && event.width === 0 && event.height === 0 || isAndroid() && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||
|
||||
// iOS VoiceOver returns 0.333• for width/height.
|
||||
event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';
|
||||
}
|
||||
function isMouseLikePointerType(pointerType, strict) {
|
||||
// On some Linux machines with Chromium, mouse inputs return a `pointerType`
|
||||
// of "pen": https://github.com/floating-ui/floating-ui/issues/2015
|
||||
const values = ['mouse', 'pen'];
|
||||
if (!strict) {
|
||||
values.push('', undefined);
|
||||
}
|
||||
return values.includes(pointerType);
|
||||
}
|
||||
|
||||
var isClient = typeof document !== 'undefined';
|
||||
|
||||
var noop = function noop() {};
|
||||
var index = isClient ? useLayoutEffect : noop;
|
||||
|
||||
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
||||
const SafeReact = {
|
||||
...React
|
||||
};
|
||||
|
||||
function useLatestRef(value) {
|
||||
const ref = React.useRef(value);
|
||||
index(() => {
|
||||
ref.current = value;
|
||||
});
|
||||
return ref;
|
||||
}
|
||||
const useInsertionEffect = SafeReact.useInsertionEffect;
|
||||
const useSafeInsertionEffect = useInsertionEffect || (fn => fn());
|
||||
function useEffectEvent(callback) {
|
||||
const ref = React.useRef(() => {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
throw new Error('Cannot call an event handler while rendering.');
|
||||
}
|
||||
});
|
||||
useSafeInsertionEffect(() => {
|
||||
ref.current = callback;
|
||||
});
|
||||
return React.useCallback(function () {
|
||||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
||||
args[_key] = arguments[_key];
|
||||
}
|
||||
return ref.current == null ? void 0 : ref.current(...args);
|
||||
}, []);
|
||||
}
|
||||
|
||||
function isDifferentGridRow(index, cols, prevRow) {
|
||||
return Math.floor(index / cols) !== prevRow;
|
||||
}
|
||||
function isIndexOutOfListBounds(listRef, index) {
|
||||
return index < 0 || index >= listRef.current.length;
|
||||
}
|
||||
function getMinListIndex(listRef, disabledIndices) {
|
||||
return findNonDisabledListIndex(listRef, {
|
||||
disabledIndices
|
||||
});
|
||||
}
|
||||
function getMaxListIndex(listRef, disabledIndices) {
|
||||
return findNonDisabledListIndex(listRef, {
|
||||
decrement: true,
|
||||
startingIndex: listRef.current.length,
|
||||
disabledIndices
|
||||
});
|
||||
}
|
||||
function findNonDisabledListIndex(listRef, _temp) {
|
||||
let {
|
||||
startingIndex = -1,
|
||||
decrement = false,
|
||||
disabledIndices,
|
||||
amount = 1
|
||||
} = _temp === void 0 ? {} : _temp;
|
||||
let index = startingIndex;
|
||||
do {
|
||||
index += decrement ? -amount : amount;
|
||||
} while (index >= 0 && index <= listRef.current.length - 1 && isListIndexDisabled(listRef, index, disabledIndices));
|
||||
return index;
|
||||
}
|
||||
function getGridNavigatedIndex(listRef, _ref) {
|
||||
let {
|
||||
event,
|
||||
orientation,
|
||||
loop,
|
||||
rtl,
|
||||
cols,
|
||||
disabledIndices,
|
||||
minIndex,
|
||||
maxIndex,
|
||||
prevIndex,
|
||||
stopEvent: stop = false
|
||||
} = _ref;
|
||||
let nextIndex = prevIndex;
|
||||
if (event.key === ARROW_UP) {
|
||||
stop && stopEvent(event);
|
||||
if (prevIndex === -1) {
|
||||
nextIndex = maxIndex;
|
||||
} else {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: nextIndex,
|
||||
amount: cols,
|
||||
decrement: true,
|
||||
disabledIndices
|
||||
});
|
||||
if (loop && (prevIndex - cols < minIndex || nextIndex < 0)) {
|
||||
const col = prevIndex % cols;
|
||||
const maxCol = maxIndex % cols;
|
||||
const offset = maxIndex - (maxCol - col);
|
||||
if (maxCol === col) {
|
||||
nextIndex = maxIndex;
|
||||
} else {
|
||||
nextIndex = maxCol > col ? offset : offset - cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isIndexOutOfListBounds(listRef, nextIndex)) {
|
||||
nextIndex = prevIndex;
|
||||
}
|
||||
}
|
||||
if (event.key === ARROW_DOWN) {
|
||||
stop && stopEvent(event);
|
||||
if (prevIndex === -1) {
|
||||
nextIndex = minIndex;
|
||||
} else {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex,
|
||||
amount: cols,
|
||||
disabledIndices
|
||||
});
|
||||
if (loop && prevIndex + cols > maxIndex) {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex % cols - cols,
|
||||
amount: cols,
|
||||
disabledIndices
|
||||
});
|
||||
}
|
||||
}
|
||||
if (isIndexOutOfListBounds(listRef, nextIndex)) {
|
||||
nextIndex = prevIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Remains on the same row/column.
|
||||
if (orientation === 'both') {
|
||||
const prevRow = floor(prevIndex / cols);
|
||||
if (event.key === (rtl ? ARROW_LEFT : ARROW_RIGHT)) {
|
||||
stop && stopEvent(event);
|
||||
if (prevIndex % cols !== cols - 1) {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex,
|
||||
disabledIndices
|
||||
});
|
||||
if (loop && isDifferentGridRow(nextIndex, cols, prevRow)) {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex - prevIndex % cols - 1,
|
||||
disabledIndices
|
||||
});
|
||||
}
|
||||
} else if (loop) {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex - prevIndex % cols - 1,
|
||||
disabledIndices
|
||||
});
|
||||
}
|
||||
if (isDifferentGridRow(nextIndex, cols, prevRow)) {
|
||||
nextIndex = prevIndex;
|
||||
}
|
||||
}
|
||||
if (event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT)) {
|
||||
stop && stopEvent(event);
|
||||
if (prevIndex % cols !== 0) {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex,
|
||||
decrement: true,
|
||||
disabledIndices
|
||||
});
|
||||
if (loop && isDifferentGridRow(nextIndex, cols, prevRow)) {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex + (cols - prevIndex % cols),
|
||||
decrement: true,
|
||||
disabledIndices
|
||||
});
|
||||
}
|
||||
} else if (loop) {
|
||||
nextIndex = findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex + (cols - prevIndex % cols),
|
||||
decrement: true,
|
||||
disabledIndices
|
||||
});
|
||||
}
|
||||
if (isDifferentGridRow(nextIndex, cols, prevRow)) {
|
||||
nextIndex = prevIndex;
|
||||
}
|
||||
}
|
||||
const lastRow = floor(maxIndex / cols) === prevRow;
|
||||
if (isIndexOutOfListBounds(listRef, nextIndex)) {
|
||||
if (loop && lastRow) {
|
||||
nextIndex = event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT) ? maxIndex : findNonDisabledListIndex(listRef, {
|
||||
startingIndex: prevIndex - prevIndex % cols - 1,
|
||||
disabledIndices
|
||||
});
|
||||
} else {
|
||||
nextIndex = prevIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nextIndex;
|
||||
}
|
||||
|
||||
/** For each cell index, gets the item index that occupies that cell */
|
||||
function createGridCellMap(sizes, cols, dense) {
|
||||
const cellMap = [];
|
||||
let startIndex = 0;
|
||||
sizes.forEach((_ref2, index) => {
|
||||
let {
|
||||
width,
|
||||
height
|
||||
} = _ref2;
|
||||
if (width > cols) {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
throw new Error("[Floating UI]: Invalid grid - item width at index " + index + " is greater than grid columns");
|
||||
}
|
||||
}
|
||||
let itemPlaced = false;
|
||||
if (dense) {
|
||||
startIndex = 0;
|
||||
}
|
||||
while (!itemPlaced) {
|
||||
const targetCells = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
for (let j = 0; j < height; j++) {
|
||||
targetCells.push(startIndex + i + j * cols);
|
||||
}
|
||||
}
|
||||
if (startIndex % cols + width <= cols && targetCells.every(cell => cellMap[cell] == null)) {
|
||||
targetCells.forEach(cell => {
|
||||
cellMap[cell] = index;
|
||||
});
|
||||
itemPlaced = true;
|
||||
} else {
|
||||
startIndex++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// convert into a non-sparse array
|
||||
return [...cellMap];
|
||||
}
|
||||
|
||||
/** Gets cell index of an item's corner or -1 when index is -1. */
|
||||
function getGridCellIndexOfCorner(index, sizes, cellMap, cols, corner) {
|
||||
if (index === -1) return -1;
|
||||
const firstCellIndex = cellMap.indexOf(index);
|
||||
const sizeItem = sizes[index];
|
||||
switch (corner) {
|
||||
case 'tl':
|
||||
return firstCellIndex;
|
||||
case 'tr':
|
||||
if (!sizeItem) {
|
||||
return firstCellIndex;
|
||||
}
|
||||
return firstCellIndex + sizeItem.width - 1;
|
||||
case 'bl':
|
||||
if (!sizeItem) {
|
||||
return firstCellIndex;
|
||||
}
|
||||
return firstCellIndex + (sizeItem.height - 1) * cols;
|
||||
case 'br':
|
||||
return cellMap.lastIndexOf(index);
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets all cell indices that correspond to the specified indices */
|
||||
function getGridCellIndices(indices, cellMap) {
|
||||
return cellMap.flatMap((index, cellIndex) => indices.includes(index) ? [cellIndex] : []);
|
||||
}
|
||||
function isListIndexDisabled(listRef, index, disabledIndices) {
|
||||
if (typeof disabledIndices === 'function') {
|
||||
return disabledIndices(index);
|
||||
} else if (disabledIndices) {
|
||||
return disabledIndices.includes(index);
|
||||
}
|
||||
const element = listRef.current[index];
|
||||
return element == null || element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';
|
||||
}
|
||||
|
||||
const getTabbableOptions = () => ({
|
||||
getShadowRoot: true,
|
||||
displayCheck:
|
||||
// JSDOM does not support the `tabbable` library. To solve this we can
|
||||
// check if `ResizeObserver` is a real function (not polyfilled), which
|
||||
// determines if the current environment is JSDOM-like.
|
||||
typeof ResizeObserver === 'function' && ResizeObserver.toString().includes('[native code]') ? 'full' : 'none'
|
||||
});
|
||||
function getTabbableIn(container, dir) {
|
||||
const list = tabbable(container, getTabbableOptions());
|
||||
const len = list.length;
|
||||
if (len === 0) return;
|
||||
const active = activeElement(getDocument(container));
|
||||
const index = list.indexOf(active);
|
||||
const nextIndex = index === -1 ? dir === 1 ? 0 : len - 1 : index + dir;
|
||||
return list[nextIndex];
|
||||
}
|
||||
function getNextTabbable(referenceElement) {
|
||||
return getTabbableIn(getDocument(referenceElement).body, 1) || referenceElement;
|
||||
}
|
||||
function getPreviousTabbable(referenceElement) {
|
||||
return getTabbableIn(getDocument(referenceElement).body, -1) || referenceElement;
|
||||
}
|
||||
function isOutsideEvent(event, container) {
|
||||
const containerElement = container || event.currentTarget;
|
||||
const relatedTarget = event.relatedTarget;
|
||||
return !relatedTarget || !contains(containerElement, relatedTarget);
|
||||
}
|
||||
function disableFocusInside(container) {
|
||||
const tabbableElements = tabbable(container, getTabbableOptions());
|
||||
tabbableElements.forEach(element => {
|
||||
element.dataset.tabindex = element.getAttribute('tabindex') || '';
|
||||
element.setAttribute('tabindex', '-1');
|
||||
});
|
||||
}
|
||||
function enableFocusInside(container) {
|
||||
const elements = container.querySelectorAll('[data-tabindex]');
|
||||
elements.forEach(element => {
|
||||
const tabindex = element.dataset.tabindex;
|
||||
delete element.dataset.tabindex;
|
||||
if (tabindex) {
|
||||
element.setAttribute('tabindex', tabindex);
|
||||
} else {
|
||||
element.removeAttribute('tabindex');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export { activeElement, contains, createGridCellMap, disableFocusInside, enableFocusInside, findNonDisabledListIndex, getDeepestNode, getDocument, getFloatingFocusElement, getGridCellIndexOfCorner, getGridCellIndices, getGridNavigatedIndex, getMaxListIndex, getMinListIndex, getNextTabbable, getNodeAncestors, getNodeChildren, getPlatform, getPreviousTabbable, getTabbableOptions, getTarget, getUserAgent, isAndroid, isDifferentGridRow, isEventTargetWithin, isIndexOutOfListBounds, isJSDOM, isListIndexDisabled, isMac, isMouseLikePointerType, isOutsideEvent, isReactEvent, isRootElement, isSafari, isTypeableCombobox, isTypeableElement, isVirtualClick, isVirtualPointerEvent, matchesFocusVisible, stopEvent, useEffectEvent, useLatestRef, index as useModernLayoutEffect };
|
||||
+46
-12
@@ -1,3 +1,6 @@
|
||||
function hasWindow() {
|
||||
return typeof window !== 'undefined';
|
||||
}
|
||||
function getNodeName(node) {
|
||||
if (isNode(node)) {
|
||||
return (node.nodeName || '').toLowerCase();
|
||||
@@ -16,21 +19,30 @@ function getDocumentElement(node) {
|
||||
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) {
|
||||
// Browsers without `ShadowRoot` support.
|
||||
if (typeof ShadowRoot === 'undefined') {
|
||||
if (!hasWindow() || typeof ShadowRoot === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
|
||||
}
|
||||
const invalidOverflowDisplayValues = /*#__PURE__*/new Set(['inline', 'contents']);
|
||||
function isOverflowElement(element) {
|
||||
const {
|
||||
overflow,
|
||||
@@ -38,23 +50,40 @@ function isOverflowElement(element) {
|
||||
overflowY,
|
||||
display
|
||||
} = getComputedStyle(element);
|
||||
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !['inline', 'contents'].includes(display);
|
||||
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !invalidOverflowDisplayValues.has(display);
|
||||
}
|
||||
const tableElements = /*#__PURE__*/new Set(['table', 'td', 'th']);
|
||||
function isTableElement(element) {
|
||||
return ['table', 'td', 'th'].includes(getNodeName(element));
|
||||
return tableElements.has(getNodeName(element));
|
||||
}
|
||||
function isContainingBlock(element) {
|
||||
const topLayerSelectors = [':popover-open', ':modal'];
|
||||
function isTopLayer(element) {
|
||||
return topLayerSelectors.some(selector => {
|
||||
try {
|
||||
return element.matches(selector);
|
||||
} catch (_e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
const transformProperties = ['transform', 'translate', 'scale', 'rotate', 'perspective'];
|
||||
const willChangeValues = ['transform', 'translate', 'scale', 'rotate', 'perspective', 'filter'];
|
||||
const containValues = ['paint', 'layout', 'strict', 'content'];
|
||||
function isContainingBlock(elementOrCss) {
|
||||
const webkit = isWebKit();
|
||||
const css = getComputedStyle(element);
|
||||
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));
|
||||
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
||||
return transformProperties.some(value => css[value] ? css[value] !== 'none' : false) || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || willChangeValues.some(value => (css.willChange || '').includes(value)) || containValues.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);
|
||||
}
|
||||
@@ -64,8 +93,9 @@ function isWebKit() {
|
||||
if (typeof CSS === 'undefined' || !CSS.supports) return false;
|
||||
return CSS.supports('-webkit-backdrop-filter', 'none');
|
||||
}
|
||||
const lastTraversableNodeNames = /*#__PURE__*/new Set(['html', 'body', '#document']);
|
||||
function isLastTraversableNode(node) {
|
||||
return ['html', 'body', '#document'].includes(getNodeName(node));
|
||||
return lastTraversableNodeNames.has(getNodeName(node));
|
||||
}
|
||||
function getComputedStyle(element) {
|
||||
return getWindow(element).getComputedStyle(element);
|
||||
@@ -78,8 +108,8 @@ function getNodeScroll(element) {
|
||||
};
|
||||
}
|
||||
return {
|
||||
scrollLeft: element.pageXOffset,
|
||||
scrollTop: element.pageYOffset
|
||||
scrollLeft: element.scrollX,
|
||||
scrollTop: element.scrollY
|
||||
};
|
||||
}
|
||||
function getParentNode(node) {
|
||||
@@ -119,9 +149,13 @@ function getOverflowAncestors(node, list, traverseIframes) {
|
||||
const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
|
||||
const win = getWindow(scrollableAncestor);
|
||||
if (isBody) {
|
||||
return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], win.frameElement && traverseIframes ? getOverflowAncestors(win.frameElement) : []);
|
||||
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;
|
||||
}
|
||||
|
||||
export { getComputedStyle, getContainingBlock, getDocumentElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isWebKit };
|
||||
export { getComputedStyle, getContainingBlock, getDocumentElement, getFrameElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isTopLayer, isWebKit };
|
||||
|
||||
+9
-8
@@ -42,8 +42,9 @@ function getOppositeAxis(axis) {
|
||||
function getAxisLength(axis) {
|
||||
return axis === 'y' ? 'height' : 'width';
|
||||
}
|
||||
const yAxisSides = /*#__PURE__*/new Set(['top', 'bottom']);
|
||||
function getSideAxis(placement) {
|
||||
return ['top', 'bottom'].includes(getSide(placement)) ? 'y' : 'x';
|
||||
return yAxisSides.has(getSide(placement)) ? 'y' : 'x';
|
||||
}
|
||||
function getAlignmentAxis(placement) {
|
||||
return getOppositeAxis(getSideAxis(placement));
|
||||
@@ -68,19 +69,19 @@ function getExpandedPlacements(placement) {
|
||||
function getOppositeAlignmentPlacement(placement) {
|
||||
return placement.replace(/start|end/g, alignment => oppositeAlignmentMap[alignment]);
|
||||
}
|
||||
const lrPlacement = ['left', 'right'];
|
||||
const rlPlacement = ['right', 'left'];
|
||||
const tbPlacement = ['top', 'bottom'];
|
||||
const btPlacement = ['bottom', 'top'];
|
||||
function getSideList(side, isStart, rtl) {
|
||||
const lr = ['left', 'right'];
|
||||
const rl = ['right', 'left'];
|
||||
const tb = ['top', 'bottom'];
|
||||
const bt = ['bottom', 'top'];
|
||||
switch (side) {
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
if (rtl) return isStart ? rl : lr;
|
||||
return isStart ? lr : rl;
|
||||
if (rtl) return isStart ? rlPlacement : lrPlacement;
|
||||
return isStart ? lrPlacement : rlPlacement;
|
||||
case 'left':
|
||||
case 'right':
|
||||
return isStart ? tb : bt;
|
||||
return isStart ? tbPlacement : btPlacement;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user