|
|
@@ -0,0 +1,1046 @@
|
|
|
+import { getSideAxis, getAlignmentAxis, getAxisLength, getSide, getAlignment, evaluate, getPaddingObject, rectToClientRect, min, clamp, placements, getAlignmentSides, getOppositeAlignmentPlacement, getOppositePlacement, getExpandedPlacements, getOppositeAxisPlacements, sides, max, getOppositeAxis } from '@floating-ui/utils';
|
|
|
+export { rectToClientRect } from '@floating-ui/utils';
|
|
|
+
|
|
|
+function computeCoordsFromPlacement(_ref, placement, rtl) {
|
|
|
+ let {
|
|
|
+ reference,
|
|
|
+ floating
|
|
|
+ } = _ref;
|
|
|
+ const sideAxis = getSideAxis(placement);
|
|
|
+ const alignmentAxis = getAlignmentAxis(placement);
|
|
|
+ const alignLength = getAxisLength(alignmentAxis);
|
|
|
+ const side = getSide(placement);
|
|
|
+ const isVertical = sideAxis === 'y';
|
|
|
+ const commonX = reference.x + reference.width / 2 - floating.width / 2;
|
|
|
+ const commonY = reference.y + reference.height / 2 - floating.height / 2;
|
|
|
+ const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;
|
|
|
+ let coords;
|
|
|
+ switch (side) {
|
|
|
+ case 'top':
|
|
|
+ coords = {
|
|
|
+ x: commonX,
|
|
|
+ y: reference.y - floating.height
|
|
|
+ };
|
|
|
+ break;
|
|
|
+ case 'bottom':
|
|
|
+ coords = {
|
|
|
+ x: commonX,
|
|
|
+ y: reference.y + reference.height
|
|
|
+ };
|
|
|
+ break;
|
|
|
+ case 'right':
|
|
|
+ coords = {
|
|
|
+ x: reference.x + reference.width,
|
|
|
+ y: commonY
|
|
|
+ };
|
|
|
+ break;
|
|
|
+ case 'left':
|
|
|
+ coords = {
|
|
|
+ x: reference.x - floating.width,
|
|
|
+ y: commonY
|
|
|
+ };
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ coords = {
|
|
|
+ x: reference.x,
|
|
|
+ y: reference.y
|
|
|
+ };
|
|
|
+ }
|
|
|
+ switch (getAlignment(placement)) {
|
|
|
+ case 'start':
|
|
|
+ coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);
|
|
|
+ break;
|
|
|
+ case 'end':
|
|
|
+ coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ 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.
|
|
|
+ * - 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
|
|
|
+ */
|
|
|
+async function detectOverflow(state, options) {
|
|
|
+ var _await$platform$isEle;
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ const {
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ platform,
|
|
|
+ rects,
|
|
|
+ elements,
|
|
|
+ strategy
|
|
|
+ } = state;
|
|
|
+ const {
|
|
|
+ boundary = 'clippingAncestors',
|
|
|
+ rootBoundary = 'viewport',
|
|
|
+ elementContext = 'floating',
|
|
|
+ altBoundary = false,
|
|
|
+ padding = 0
|
|
|
+ } = evaluate(options, state);
|
|
|
+ const paddingObject = getPaddingObject(padding);
|
|
|
+ const altContext = elementContext === 'floating' ? 'reference' : 'floating';
|
|
|
+ const element = elements[altBoundary ? altContext : elementContext];
|
|
|
+ const clippingClientRect = rectToClientRect(await platform.getClippingRect({
|
|
|
+ element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),
|
|
|
+ boundary,
|
|
|
+ rootBoundary,
|
|
|
+ strategy
|
|
|
+ }));
|
|
|
+ const rect = elementContext === 'floating' ? {
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ width: rects.floating.width,
|
|
|
+ height: rects.floating.height
|
|
|
+ } : rects.reference;
|
|
|
+ const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
|
|
|
+ const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
|
|
|
+ x: 1,
|
|
|
+ y: 1
|
|
|
+ } : {
|
|
|
+ x: 1,
|
|
|
+ y: 1
|
|
|
+ };
|
|
|
+ const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
|
|
|
+ elements,
|
|
|
+ rect,
|
|
|
+ offsetParent,
|
|
|
+ strategy
|
|
|
+ }) : rect);
|
|
|
+ return {
|
|
|
+ top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
|
|
|
+ bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
|
|
|
+ left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
|
|
|
+ right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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 = options => ({
|
|
|
+ name: 'arrow',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ const {
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ placement,
|
|
|
+ rects,
|
|
|
+ platform,
|
|
|
+ elements,
|
|
|
+ middlewareData
|
|
|
+ } = state;
|
|
|
+ // Since `element` is required, we don't Partial<> the type.
|
|
|
+ const {
|
|
|
+ element,
|
|
|
+ padding = 0
|
|
|
+ } = evaluate(options, state) || {};
|
|
|
+ if (element == null) {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ const paddingObject = getPaddingObject(padding);
|
|
|
+ const coords = {
|
|
|
+ x,
|
|
|
+ y
|
|
|
+ };
|
|
|
+ const axis = getAlignmentAxis(placement);
|
|
|
+ const length = getAxisLength(axis);
|
|
|
+ const arrowDimensions = await platform.getDimensions(element);
|
|
|
+ const isYAxis = axis === 'y';
|
|
|
+ const minProp = isYAxis ? 'top' : 'left';
|
|
|
+ const maxProp = isYAxis ? 'bottom' : 'right';
|
|
|
+ const clientProp = isYAxis ? 'clientHeight' : 'clientWidth';
|
|
|
+ const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];
|
|
|
+ const startDiff = coords[axis] - rects.reference[axis];
|
|
|
+ const arrowOffsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(element));
|
|
|
+ let clientSize = arrowOffsetParent ? arrowOffsetParent[clientProp] : 0;
|
|
|
+
|
|
|
+ // DOM platform can return `window` as the `offsetParent`.
|
|
|
+ if (!clientSize || !(await (platform.isElement == null ? void 0 : platform.isElement(arrowOffsetParent)))) {
|
|
|
+ clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
|
+ }
|
|
|
+ const centerToReference = endDiff / 2 - startDiff / 2;
|
|
|
+
|
|
|
+ // If the padding is large enough that it causes the arrow to no longer be
|
|
|
+ // centered, modify the padding so that it is centered.
|
|
|
+ const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;
|
|
|
+ const minPadding = min(paddingObject[minProp], largestPossiblePadding);
|
|
|
+ const maxPadding = min(paddingObject[maxProp], largestPossiblePadding);
|
|
|
+
|
|
|
+ // Make sure the arrow doesn't overflow the floating element if the center
|
|
|
+ // point is outside the floating element's bounds.
|
|
|
+ const min$1 = minPadding;
|
|
|
+ const max = clientSize - arrowDimensions[length] - maxPadding;
|
|
|
+ const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
|
|
|
+ const offset = clamp(min$1, center, max);
|
|
|
+
|
|
|
+ // If the reference is small enough that the arrow's padding causes it to
|
|
|
+ // to point to nothing for an aligned placement, adjust the offset of the
|
|
|
+ // floating element itself. To ensure `shift()` continues to take action,
|
|
|
+ // a single reset is performed when this is true.
|
|
|
+ const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min$1 ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
|
|
|
+ const alignmentOffset = shouldAddOffset ? center < min$1 ? center - min$1 : center - max : 0;
|
|
|
+ return {
|
|
|
+ [axis]: coords[axis] + alignmentOffset,
|
|
|
+ data: {
|
|
|
+ [axis]: offset,
|
|
|
+ centerOffset: center - offset - alignmentOffset,
|
|
|
+ ...(shouldAddOffset && {
|
|
|
+ alignmentOffset
|
|
|
+ })
|
|
|
+ },
|
|
|
+ reset: shouldAddOffset
|
|
|
+ };
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+function getPlacementList(alignment, autoAlignment, allowedPlacements) {
|
|
|
+ const allowedPlacementsSortedByAlignment = alignment ? [...allowedPlacements.filter(placement => getAlignment(placement) === alignment), ...allowedPlacements.filter(placement => getAlignment(placement) !== alignment)] : allowedPlacements.filter(placement => getSide(placement) === placement);
|
|
|
+ return allowedPlacementsSortedByAlignment.filter(placement => {
|
|
|
+ if (alignment) {
|
|
|
+ return getAlignment(placement) === alignment || (autoAlignment ? getOppositeAlignmentPlacement(placement) !== placement : false);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 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 = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: 'autoPlacement',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ var _middlewareData$autoP, _middlewareData$autoP2, _placementsThatFitOnE;
|
|
|
+ const {
|
|
|
+ rects,
|
|
|
+ middlewareData,
|
|
|
+ placement,
|
|
|
+ platform,
|
|
|
+ elements
|
|
|
+ } = state;
|
|
|
+ const {
|
|
|
+ crossAxis = false,
|
|
|
+ alignment,
|
|
|
+ allowedPlacements = placements,
|
|
|
+ autoAlignment = true,
|
|
|
+ ...detectOverflowOptions
|
|
|
+ } = evaluate(options, state);
|
|
|
+ const placements$1 = alignment !== undefined || allowedPlacements === placements ? getPlacementList(alignment || null, autoAlignment, allowedPlacements) : allowedPlacements;
|
|
|
+ const overflow = await detectOverflow(state, detectOverflowOptions);
|
|
|
+ const currentIndex = ((_middlewareData$autoP = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP.index) || 0;
|
|
|
+ const currentPlacement = placements$1[currentIndex];
|
|
|
+ if (currentPlacement == null) {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ const alignmentSides = getAlignmentSides(currentPlacement, rects, await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating)));
|
|
|
+
|
|
|
+ // Make `computeCoords` start from the right place.
|
|
|
+ if (placement !== currentPlacement) {
|
|
|
+ return {
|
|
|
+ reset: {
|
|
|
+ placement: placements$1[0]
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ const currentOverflows = [overflow[getSide(currentPlacement)], overflow[alignmentSides[0]], overflow[alignmentSides[1]]];
|
|
|
+ const allOverflows = [...(((_middlewareData$autoP2 = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP2.overflows) || []), {
|
|
|
+ placement: currentPlacement,
|
|
|
+ overflows: currentOverflows
|
|
|
+ }];
|
|
|
+ const nextPlacement = placements$1[currentIndex + 1];
|
|
|
+
|
|
|
+ // There are more placements to check.
|
|
|
+ if (nextPlacement) {
|
|
|
+ return {
|
|
|
+ data: {
|
|
|
+ index: currentIndex + 1,
|
|
|
+ overflows: allOverflows
|
|
|
+ },
|
|
|
+ reset: {
|
|
|
+ placement: nextPlacement
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ const placementsSortedByMostSpace = allOverflows.map(d => {
|
|
|
+ const alignment = getAlignment(d.placement);
|
|
|
+ return [d.placement, alignment && crossAxis ?
|
|
|
+ // Check along the mainAxis and main crossAxis side.
|
|
|
+ d.overflows.slice(0, 2).reduce((acc, v) => acc + v, 0) :
|
|
|
+ // Check only the mainAxis.
|
|
|
+ d.overflows[0], d.overflows];
|
|
|
+ }).sort((a, b) => a[1] - b[1]);
|
|
|
+ const placementsThatFitOnEachSide = placementsSortedByMostSpace.filter(d => d[2].slice(0,
|
|
|
+ // Aligned placements should not check their opposite crossAxis
|
|
|
+ // side.
|
|
|
+ getAlignment(d[0]) ? 2 : 3).every(v => v <= 0));
|
|
|
+ const resetPlacement = ((_placementsThatFitOnE = placementsThatFitOnEachSide[0]) == null ? void 0 : _placementsThatFitOnE[0]) || placementsSortedByMostSpace[0][0];
|
|
|
+ if (resetPlacement !== placement) {
|
|
|
+ return {
|
|
|
+ data: {
|
|
|
+ index: currentIndex + 1,
|
|
|
+ overflows: allOverflows
|
|
|
+ },
|
|
|
+ reset: {
|
|
|
+ placement: resetPlacement
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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 = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: 'flip',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ var _middlewareData$arrow, _middlewareData$flip;
|
|
|
+ const {
|
|
|
+ placement,
|
|
|
+ middlewareData,
|
|
|
+ rects,
|
|
|
+ initialPlacement,
|
|
|
+ platform,
|
|
|
+ elements
|
|
|
+ } = state;
|
|
|
+ const {
|
|
|
+ mainAxis: checkMainAxis = true,
|
|
|
+ crossAxis: checkCrossAxis = true,
|
|
|
+ fallbackPlacements: specifiedFallbackPlacements,
|
|
|
+ fallbackStrategy = 'bestFit',
|
|
|
+ fallbackAxisSideDirection = 'none',
|
|
|
+ flipAlignment = true,
|
|
|
+ ...detectOverflowOptions
|
|
|
+ } = evaluate(options, state);
|
|
|
+
|
|
|
+ // If a reset by the arrow was caused due to an alignment offset being
|
|
|
+ // added, we should skip any logic now since `flip()` has already done its
|
|
|
+ // work.
|
|
|
+ // https://github.com/floating-ui/floating-ui/issues/2549#issuecomment-1719601643
|
|
|
+ if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
|
|
|
+ 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));
|
|
|
+ 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 overflows = [];
|
|
|
+ let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
|
|
|
+ if (checkMainAxis) {
|
|
|
+ overflows.push(overflow[side]);
|
|
|
+ }
|
|
|
+ if (checkCrossAxis) {
|
|
|
+ const sides = getAlignmentSides(placement, rects, rtl);
|
|
|
+ overflows.push(overflow[sides[0]], overflow[sides[1]]);
|
|
|
+ }
|
|
|
+ overflowsData = [...overflowsData, {
|
|
|
+ placement,
|
|
|
+ overflows
|
|
|
+ }];
|
|
|
+
|
|
|
+ // One or more sides is overflowing.
|
|
|
+ if (!overflows.every(side => side <= 0)) {
|
|
|
+ var _middlewareData$flip2, _overflowsData$filter;
|
|
|
+ const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
|
|
|
+ const nextPlacement = placements[nextIndex];
|
|
|
+ if (nextPlacement) {
|
|
|
+ var _overflowsData$;
|
|
|
+ const ignoreCrossAxisOverflow = checkCrossAxis === 'alignment' ? initialSideAxis !== getSideAxis(nextPlacement) : false;
|
|
|
+ const hasInitialMainAxisOverflow = ((_overflowsData$ = overflowsData[0]) == null ? void 0 : _overflowsData$.overflows[0]) > 0;
|
|
|
+ if (!ignoreCrossAxisOverflow || hasInitialMainAxisOverflow) {
|
|
|
+ // 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,
|
|
|
+ // then find the placement that fits the best on the main crossAxis side.
|
|
|
+ let resetPlacement = (_overflowsData$filter = overflowsData.filter(d => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
|
|
|
+
|
|
|
+ // Otherwise fallback.
|
|
|
+ if (!resetPlacement) {
|
|
|
+ switch (fallbackStrategy) {
|
|
|
+ case 'bestFit':
|
|
|
+ {
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'initialPlacement':
|
|
|
+ resetPlacement = initialPlacement;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (placement !== resetPlacement) {
|
|
|
+ return {
|
|
|
+ reset: {
|
|
|
+ placement: resetPlacement
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+function getSideOffsets(overflow, rect) {
|
|
|
+ return {
|
|
|
+ top: overflow.top - rect.height,
|
|
|
+ right: overflow.right - rect.width,
|
|
|
+ bottom: overflow.bottom - rect.height,
|
|
|
+ left: overflow.left - rect.width
|
|
|
+ };
|
|
|
+}
|
|
|
+function isAnySideFullyClipped(overflow) {
|
|
|
+ return sides.some(side => overflow[side] >= 0);
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 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 = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: 'hide',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ const {
|
|
|
+ rects
|
|
|
+ } = state;
|
|
|
+ const {
|
|
|
+ strategy = 'referenceHidden',
|
|
|
+ ...detectOverflowOptions
|
|
|
+ } = evaluate(options, state);
|
|
|
+ switch (strategy) {
|
|
|
+ case 'referenceHidden':
|
|
|
+ {
|
|
|
+ const overflow = await detectOverflow(state, {
|
|
|
+ ...detectOverflowOptions,
|
|
|
+ elementContext: 'reference'
|
|
|
+ });
|
|
|
+ const offsets = getSideOffsets(overflow, rects.reference);
|
|
|
+ return {
|
|
|
+ data: {
|
|
|
+ referenceHiddenOffsets: offsets,
|
|
|
+ referenceHidden: isAnySideFullyClipped(offsets)
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ case 'escaped':
|
|
|
+ {
|
|
|
+ const overflow = await detectOverflow(state, {
|
|
|
+ ...detectOverflowOptions,
|
|
|
+ altBoundary: true
|
|
|
+ });
|
|
|
+ const offsets = getSideOffsets(overflow, rects.floating);
|
|
|
+ return {
|
|
|
+ data: {
|
|
|
+ escapedOffsets: offsets,
|
|
|
+ escaped: isAnySideFullyClipped(offsets)
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+function getBoundingRect(rects) {
|
|
|
+ const minX = min(...rects.map(rect => rect.left));
|
|
|
+ const minY = min(...rects.map(rect => rect.top));
|
|
|
+ const maxX = max(...rects.map(rect => rect.right));
|
|
|
+ const maxY = max(...rects.map(rect => rect.bottom));
|
|
|
+ return {
|
|
|
+ x: minX,
|
|
|
+ y: minY,
|
|
|
+ width: maxX - minX,
|
|
|
+ height: maxY - minY
|
|
|
+ };
|
|
|
+}
|
|
|
+function getRectsByLine(rects) {
|
|
|
+ const sortedRects = rects.slice().sort((a, b) => a.y - b.y);
|
|
|
+ const groups = [];
|
|
|
+ let prevRect = null;
|
|
|
+ for (let i = 0; i < sortedRects.length; i++) {
|
|
|
+ const rect = sortedRects[i];
|
|
|
+ if (!prevRect || rect.y - prevRect.y > prevRect.height / 2) {
|
|
|
+ groups.push([rect]);
|
|
|
+ } else {
|
|
|
+ groups[groups.length - 1].push(rect);
|
|
|
+ }
|
|
|
+ prevRect = rect;
|
|
|
+ }
|
|
|
+ return groups.map(rect => rectToClientRect(getBoundingRect(rect)));
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 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 = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: 'inline',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ const {
|
|
|
+ placement,
|
|
|
+ elements,
|
|
|
+ rects,
|
|
|
+ platform,
|
|
|
+ strategy
|
|
|
+ } = state;
|
|
|
+ // A MouseEvent's client{X,Y} coords can be up to 2 pixels off a
|
|
|
+ // ClientRect's bounds, despite the event listener being triggered. A
|
|
|
+ // padding of 2 seems to handle this issue.
|
|
|
+ const {
|
|
|
+ padding = 2,
|
|
|
+ x,
|
|
|
+ y
|
|
|
+ } = evaluate(options, state);
|
|
|
+ const nativeClientRects = Array.from((await (platform.getClientRects == null ? void 0 : platform.getClientRects(elements.reference))) || []);
|
|
|
+ const clientRects = getRectsByLine(nativeClientRects);
|
|
|
+ const fallback = rectToClientRect(getBoundingRect(nativeClientRects));
|
|
|
+ const paddingObject = getPaddingObject(padding);
|
|
|
+ function getBoundingClientRect() {
|
|
|
+ // There are two rects and they are disjoined.
|
|
|
+ if (clientRects.length === 2 && clientRects[0].left > clientRects[1].right && x != null && y != null) {
|
|
|
+ // Find the first rect in which the point is fully inside.
|
|
|
+ return clientRects.find(rect => x > rect.left - paddingObject.left && x < rect.right + paddingObject.right && y > rect.top - paddingObject.top && y < rect.bottom + paddingObject.bottom) || fallback;
|
|
|
+ }
|
|
|
+
|
|
|
+ // There are 2 or more connected rects.
|
|
|
+ if (clientRects.length >= 2) {
|
|
|
+ if (getSideAxis(placement) === 'y') {
|
|
|
+ const firstRect = clientRects[0];
|
|
|
+ const lastRect = clientRects[clientRects.length - 1];
|
|
|
+ const isTop = getSide(placement) === 'top';
|
|
|
+ const top = firstRect.top;
|
|
|
+ const bottom = lastRect.bottom;
|
|
|
+ const left = isTop ? firstRect.left : lastRect.left;
|
|
|
+ const right = isTop ? firstRect.right : lastRect.right;
|
|
|
+ const width = right - left;
|
|
|
+ const height = bottom - top;
|
|
|
+ return {
|
|
|
+ top,
|
|
|
+ bottom,
|
|
|
+ left,
|
|
|
+ right,
|
|
|
+ width,
|
|
|
+ height,
|
|
|
+ x: left,
|
|
|
+ y: top
|
|
|
+ };
|
|
|
+ }
|
|
|
+ const isLeftSide = getSide(placement) === 'left';
|
|
|
+ const maxRight = max(...clientRects.map(rect => rect.right));
|
|
|
+ const minLeft = min(...clientRects.map(rect => rect.left));
|
|
|
+ const measureRects = clientRects.filter(rect => isLeftSide ? rect.left === minLeft : rect.right === maxRight);
|
|
|
+ const top = measureRects[0].top;
|
|
|
+ const bottom = measureRects[measureRects.length - 1].bottom;
|
|
|
+ const left = minLeft;
|
|
|
+ const right = maxRight;
|
|
|
+ const width = right - left;
|
|
|
+ const height = bottom - top;
|
|
|
+ return {
|
|
|
+ top,
|
|
|
+ bottom,
|
|
|
+ left,
|
|
|
+ right,
|
|
|
+ width,
|
|
|
+ height,
|
|
|
+ x: left,
|
|
|
+ y: top
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return fallback;
|
|
|
+ }
|
|
|
+ const resetRects = await platform.getElementRects({
|
|
|
+ reference: {
|
|
|
+ getBoundingClientRect
|
|
|
+ },
|
|
|
+ floating: elements.floating,
|
|
|
+ strategy
|
|
|
+ });
|
|
|
+ if (rects.reference.x !== resetRects.reference.x || rects.reference.y !== resetRects.reference.y || rects.reference.width !== resetRects.reference.width || rects.reference.height !== resetRects.reference.height) {
|
|
|
+ return {
|
|
|
+ reset: {
|
|
|
+ rects: resetRects
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// For type backwards-compatibility, the `OffsetOptions` type was also
|
|
|
+// Derivable.
|
|
|
+
|
|
|
+async function convertValueToCoords(state, options) {
|
|
|
+ const {
|
|
|
+ placement,
|
|
|
+ platform,
|
|
|
+ elements
|
|
|
+ } = state;
|
|
|
+ const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
|
|
|
+ const side = getSide(placement);
|
|
|
+ const alignment = getAlignment(placement);
|
|
|
+ const isVertical = getSideAxis(placement) === 'y';
|
|
|
+ const mainAxisMulti = ['left', 'top'].includes(side) ? -1 : 1;
|
|
|
+ const crossAxisMulti = rtl && isVertical ? -1 : 1;
|
|
|
+ const rawValue = evaluate(options, state);
|
|
|
+
|
|
|
+ // eslint-disable-next-line prefer-const
|
|
|
+ let {
|
|
|
+ mainAxis,
|
|
|
+ crossAxis,
|
|
|
+ alignmentAxis
|
|
|
+ } = typeof rawValue === 'number' ? {
|
|
|
+ mainAxis: rawValue,
|
|
|
+ crossAxis: 0,
|
|
|
+ alignmentAxis: null
|
|
|
+ } : {
|
|
|
+ mainAxis: rawValue.mainAxis || 0,
|
|
|
+ crossAxis: rawValue.crossAxis || 0,
|
|
|
+ alignmentAxis: rawValue.alignmentAxis
|
|
|
+ };
|
|
|
+ if (alignment && typeof alignmentAxis === 'number') {
|
|
|
+ crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis;
|
|
|
+ }
|
|
|
+ return isVertical ? {
|
|
|
+ x: crossAxis * crossAxisMulti,
|
|
|
+ y: mainAxis * mainAxisMulti
|
|
|
+ } : {
|
|
|
+ x: mainAxis * mainAxisMulti,
|
|
|
+ y: crossAxis * crossAxisMulti
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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 = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = 0;
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: 'offset',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ var _middlewareData$offse, _middlewareData$arrow;
|
|
|
+ const {
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ placement,
|
|
|
+ middlewareData
|
|
|
+ } = state;
|
|
|
+ const diffCoords = await convertValueToCoords(state, options);
|
|
|
+
|
|
|
+ // If the placement is the same and the arrow caused an alignment offset
|
|
|
+ // then we don't need to change the positioning coordinates.
|
|
|
+ if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ x: x + diffCoords.x,
|
|
|
+ y: y + diffCoords.y,
|
|
|
+ data: {
|
|
|
+ ...diffCoords,
|
|
|
+ placement
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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 = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: 'shift',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ const {
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ placement
|
|
|
+ } = state;
|
|
|
+ const {
|
|
|
+ mainAxis: checkMainAxis = true,
|
|
|
+ crossAxis: checkCrossAxis = false,
|
|
|
+ limiter = {
|
|
|
+ fn: _ref => {
|
|
|
+ let {
|
|
|
+ x,
|
|
|
+ y
|
|
|
+ } = _ref;
|
|
|
+ return {
|
|
|
+ x,
|
|
|
+ y
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ...detectOverflowOptions
|
|
|
+ } = evaluate(options, state);
|
|
|
+ const coords = {
|
|
|
+ x,
|
|
|
+ y
|
|
|
+ };
|
|
|
+ const overflow = await detectOverflow(state, detectOverflowOptions);
|
|
|
+ const crossAxis = getSideAxis(getSide(placement));
|
|
|
+ const mainAxis = getOppositeAxis(crossAxis);
|
|
|
+ let mainAxisCoord = coords[mainAxis];
|
|
|
+ let crossAxisCoord = coords[crossAxis];
|
|
|
+ if (checkMainAxis) {
|
|
|
+ const minSide = mainAxis === 'y' ? 'top' : 'left';
|
|
|
+ const maxSide = mainAxis === 'y' ? 'bottom' : 'right';
|
|
|
+ const min = mainAxisCoord + overflow[minSide];
|
|
|
+ const max = mainAxisCoord - overflow[maxSide];
|
|
|
+ mainAxisCoord = clamp(min, mainAxisCoord, max);
|
|
|
+ }
|
|
|
+ if (checkCrossAxis) {
|
|
|
+ const minSide = crossAxis === 'y' ? 'top' : 'left';
|
|
|
+ const maxSide = crossAxis === 'y' ? 'bottom' : 'right';
|
|
|
+ const min = crossAxisCoord + overflow[minSide];
|
|
|
+ const max = crossAxisCoord - overflow[maxSide];
|
|
|
+ crossAxisCoord = clamp(min, crossAxisCoord, max);
|
|
|
+ }
|
|
|
+ const limitedCoords = limiter.fn({
|
|
|
+ ...state,
|
|
|
+ [mainAxis]: mainAxisCoord,
|
|
|
+ [crossAxis]: crossAxisCoord
|
|
|
+ });
|
|
|
+ return {
|
|
|
+ ...limitedCoords,
|
|
|
+ data: {
|
|
|
+ x: limitedCoords.x - x,
|
|
|
+ y: limitedCoords.y - y,
|
|
|
+ enabled: {
|
|
|
+ [mainAxis]: checkMainAxis,
|
|
|
+ [crossAxis]: checkCrossAxis
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+/**
|
|
|
+ * Built-in `limiter` that will stop `shift()` at a certain point.
|
|
|
+ */
|
|
|
+const limitShift = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ options,
|
|
|
+ fn(state) {
|
|
|
+ const {
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ placement,
|
|
|
+ rects,
|
|
|
+ middlewareData
|
|
|
+ } = state;
|
|
|
+ const {
|
|
|
+ offset = 0,
|
|
|
+ mainAxis: checkMainAxis = true,
|
|
|
+ crossAxis: checkCrossAxis = true
|
|
|
+ } = evaluate(options, state);
|
|
|
+ const coords = {
|
|
|
+ x,
|
|
|
+ y
|
|
|
+ };
|
|
|
+ const crossAxis = getSideAxis(placement);
|
|
|
+ const mainAxis = getOppositeAxis(crossAxis);
|
|
|
+ let mainAxisCoord = coords[mainAxis];
|
|
|
+ let crossAxisCoord = coords[crossAxis];
|
|
|
+ const rawOffset = evaluate(offset, state);
|
|
|
+ const computedOffset = typeof rawOffset === 'number' ? {
|
|
|
+ mainAxis: rawOffset,
|
|
|
+ crossAxis: 0
|
|
|
+ } : {
|
|
|
+ mainAxis: 0,
|
|
|
+ crossAxis: 0,
|
|
|
+ ...rawOffset
|
|
|
+ };
|
|
|
+ if (checkMainAxis) {
|
|
|
+ const len = mainAxis === 'y' ? 'height' : 'width';
|
|
|
+ const limitMin = rects.reference[mainAxis] - rects.floating[len] + computedOffset.mainAxis;
|
|
|
+ const limitMax = rects.reference[mainAxis] + rects.reference[len] - computedOffset.mainAxis;
|
|
|
+ if (mainAxisCoord < limitMin) {
|
|
|
+ mainAxisCoord = limitMin;
|
|
|
+ } else if (mainAxisCoord > limitMax) {
|
|
|
+ mainAxisCoord = limitMax;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (checkCrossAxis) {
|
|
|
+ var _middlewareData$offse, _middlewareData$offse2;
|
|
|
+ const len = mainAxis === 'y' ? 'width' : 'height';
|
|
|
+ const isOriginSide = ['top', 'left'].includes(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) {
|
|
|
+ crossAxisCoord = limitMin;
|
|
|
+ } else if (crossAxisCoord > limitMax) {
|
|
|
+ crossAxisCoord = limitMax;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ [mainAxis]: mainAxisCoord,
|
|
|
+ [crossAxis]: crossAxisCoord
|
|
|
+ };
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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 = function (options) {
|
|
|
+ if (options === void 0) {
|
|
|
+ options = {};
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: 'size',
|
|
|
+ options,
|
|
|
+ async fn(state) {
|
|
|
+ var _state$middlewareData, _state$middlewareData2;
|
|
|
+ const {
|
|
|
+ placement,
|
|
|
+ rects,
|
|
|
+ platform,
|
|
|
+ elements
|
|
|
+ } = state;
|
|
|
+ const {
|
|
|
+ apply = () => {},
|
|
|
+ ...detectOverflowOptions
|
|
|
+ } = evaluate(options, state);
|
|
|
+ const overflow = await detectOverflow(state, detectOverflowOptions);
|
|
|
+ const side = getSide(placement);
|
|
|
+ const alignment = getAlignment(placement);
|
|
|
+ const isYAxis = getSideAxis(placement) === 'y';
|
|
|
+ const {
|
|
|
+ width,
|
|
|
+ height
|
|
|
+ } = rects.floating;
|
|
|
+ let heightSide;
|
|
|
+ let widthSide;
|
|
|
+ if (side === 'top' || side === 'bottom') {
|
|
|
+ heightSide = side;
|
|
|
+ widthSide = alignment === ((await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))) ? 'start' : 'end') ? 'left' : 'right';
|
|
|
+ } else {
|
|
|
+ widthSide = side;
|
|
|
+ heightSide = alignment === 'end' ? 'top' : 'bottom';
|
|
|
+ }
|
|
|
+ const maximumClippingHeight = height - overflow.top - overflow.bottom;
|
|
|
+ const maximumClippingWidth = width - overflow.left - overflow.right;
|
|
|
+ const overflowAvailableHeight = min(height - overflow[heightSide], maximumClippingHeight);
|
|
|
+ const overflowAvailableWidth = min(width - overflow[widthSide], maximumClippingWidth);
|
|
|
+ const noShift = !state.middlewareData.shift;
|
|
|
+ let availableHeight = overflowAvailableHeight;
|
|
|
+ let availableWidth = overflowAvailableWidth;
|
|
|
+ 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);
|
|
|
+ const xMax = max(overflow.right, 0);
|
|
|
+ const yMin = max(overflow.top, 0);
|
|
|
+ const yMax = max(overflow.bottom, 0);
|
|
|
+ if (isYAxis) {
|
|
|
+ availableWidth = width - 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max(overflow.left, overflow.right));
|
|
|
+ } else {
|
|
|
+ availableHeight = height - 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max(overflow.top, overflow.bottom));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await apply({
|
|
|
+ ...state,
|
|
|
+ availableWidth,
|
|
|
+ availableHeight
|
|
|
+ });
|
|
|
+ const nextDimensions = await platform.getDimensions(elements.floating);
|
|
|
+ if (width !== nextDimensions.width || height !== nextDimensions.height) {
|
|
|
+ return {
|
|
|
+ reset: {
|
|
|
+ rects: true
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+export { arrow, autoPlacement, computePosition, detectOverflow, flip, hide, inline, limitShift, offset, shift, size };
|