coupdoeil
Version:
Javascript for Ruby on Rails Coupdoeil gem
1,476 lines (1,354 loc) • 77.2 kB
JavaScript
class PopoverController {
constructor(coupdoeilElement) {
this.coupdoeilElement = coupdoeilElement;
this.card = null;
this.children = new Set;
this.parent = null;
this.closingRequest = null;
}
get isOpen() {
return !!this.coupdoeilElement.dataset.popoverOpen;
}
get isClosed() {
return !this.isOpen;
}
}
const POPOVER_CLASS_NAME = "coupdoeil--popover";
const POPOVER_SELECTOR = `.${POPOVER_CLASS_NAME}`;
const POPOVER_CLOSE_BTN_SELECTOR = "[data-popover-close]";
const CLOSING_DELAY_MS = 75;
const FETCH_DELAY_MS = 100;
const OPENING_DELAY_MS = 200;
const OPTIONS = {
animation: {
getter: getAnimation
},
cache: {
getter: getCache
},
loading: {
getter: getLoading
},
offset: {
getter: getOffset
},
openingDelay: {
getter: getOpeningDelay
},
placement: {
getter: getPlacement
},
trigger: {
getter: getTrigger$1
}
};
const ORDERED_OPTIONS = [ "trigger", "loading", "cache", "openingDelay", "animation", "placement", "offset" ];
const TRIGGERS = [ "hover", "click" ];
const ANIMATIONS = [ false, "slide-in", "fade-in", "slide-out", "custom" ];
const PLACEMENTS = [ "auto", "top", "top-start", "top-end", "right", "right-start", "right-end", "bottom", "bottom-start", "bottom-end", "left", "left-start", "left-end" ];
const LOADINGS = [ "async", "preload", "lazy" ];
function parseCSSSize(value) {
if (typeof value === "number") {
return value;
} else if (/^(-?\d+\.?\d+)px$/.test(value)) {
return parseFloat(value);
} else if (/^(-?\d*\.?\d+)rem$/.test(value)) {
return parseFloat(value) * parseFloat(getComputedStyle(document.documentElement).fontSize);
}
return 0;
}
function getOffset(optionsInt) {
const offsetBits = Number(BigInt(optionsInt) >> BigInt(24));
if (offsetBits === 0) return 0;
const isNegative = (offsetBits & 1) === 1;
const isREM = (offsetBits & 2) === 2;
const decimals = offsetBits >> 2 & 1023;
const integer = offsetBits >> 12;
const CSSSize = `${isNegative ? "-" : ""}${integer}.${decimals}${isREM ? "rem" : "px"}`;
return parseCSSSize(CSSSize);
}
function getPlacement(optionsInt) {
const placementBits = optionsInt >> 8 & 65535;
let shift = 0;
let lastPlacement = null;
const placements = [];
while (lastPlacement !== "auto" && shift < 16) {
lastPlacement = PLACEMENTS[placementBits >> shift & 15];
placements.push(lastPlacement);
shift += 4;
}
return placements;
}
function getAnimation(optionsInt) {
return ANIMATIONS[optionsInt >> 5 & 7];
}
function getOpeningDelay(optionsInt) {
return (optionsInt >> 4 & 1) === 1;
}
function getCache(optionsInt) {
return (optionsInt & 8) === 8;
}
function getLoading(optionsInt) {
return LOADINGS[optionsInt >> 1 & 3];
}
function getTrigger$1(optionsInt) {
return TRIGGERS[optionsInt & 1];
}
const popoverOptions = {
animation: undefined,
cache: undefined,
loading: undefined,
offset: undefined,
openingDelay: undefined,
placement: undefined,
trigger: undefined
};
function extractOptionsFromElement(coupdoeilElement) {
const optionsInt = coupdoeilElement.popoverController.optionsInt ||= parseOtionsInt(coupdoeilElement);
const options = Object.create(popoverOptions);
for (const option of ORDERED_OPTIONS) {
options[option] = OPTIONS[option].getter(optionsInt);
}
return options;
}
function parseOtionsInt(coupdoeilElement) {
const optionsString = coupdoeilElement.getAttribute("popover-options");
return parseInt(optionsString, 36);
}
function extractOptionFromElement(coupdoeilElement, optionName) {
const optionsInt = coupdoeilElement.popoverController.optionsInt ||= parseOtionsInt(coupdoeilElement);
return OPTIONS[optionName].getter(optionsInt);
}
function getType(controller) {
return controller.coupdoeilElement.getAttribute("popover-type");
}
function getParams(controller) {
return controller.coupdoeilElement.getAttribute("popover-params");
}
function getTrigger(controller) {
return extractOptionFromElement(controller.coupdoeilElement, "trigger");
}
function triggeredOnClick(controller) {
return getTrigger(controller) === "click";
}
function noTriggeredOnClick(controller) {
return getTrigger(controller) !== "click";
}
function triggeredOnHover(controller) {
return getTrigger(controller) === "hover";
}
function notTriggeredOnHover(controller) {
return getTrigger(controller) !== "hover";
}
function preloadedContentElement(controller) {
return controller.coupdoeilElement.querySelector(".popover-content");
}
const popoverContentHTMLMap = new Map;
function cacheMapKey(controller) {
if (preloadedContentElement(controller)) {
return controller.coupdoeilElement.uniqueId;
}
return getType(controller) + getParams(controller);
}
function getPopoverContentHTML(controller) {
return popoverContentHTMLMap.get(cacheMapKey(controller));
}
function setPopoverContentHTML(controller, value) {
popoverContentHTMLMap.set(cacheMapKey(controller), value);
}
function clearPopoverContentCache() {
popoverContentHTMLMap.clear();
}
const sides = [ "top", "right", "bottom", "left" ];
const alignments = [ "start", "end" ];
const placements = sides.reduce(((acc, side) => acc.concat(side, side + "-" + alignments[0], side + "-" + alignments[1])), []);
const min = Math.min;
const max = Math.max;
const round = Math.round;
const createCoords = v => ({
x: v,
y: v
});
const oppositeSideMap = {
left: "right",
right: "left",
bottom: "top",
top: "bottom"
};
const oppositeAlignmentMap = {
start: "end",
end: "start"
};
function clamp(start, value, end) {
return max(start, min(value, end));
}
function evaluate(value, param) {
return typeof value === "function" ? value(param) : value;
}
function getSide(placement) {
return placement.split("-")[0];
}
function getAlignment(placement) {
return placement.split("-")[1];
}
function getOppositeAxis(axis) {
return axis === "x" ? "y" : "x";
}
function getAxisLength(axis) {
return axis === "y" ? "height" : "width";
}
function getSideAxis(placement) {
return [ "top", "bottom" ].includes(getSide(placement)) ? "y" : "x";
}
function getAlignmentAxis(placement) {
return getOppositeAxis(getSideAxis(placement));
}
function getAlignmentSides(placement, rects, rtl) {
if (rtl === void 0) {
rtl = false;
}
const alignment = getAlignment(placement);
const alignmentAxis = getAlignmentAxis(placement);
const length = getAxisLength(alignmentAxis);
let mainAlignmentSide = alignmentAxis === "x" ? alignment === (rtl ? "end" : "start") ? "right" : "left" : alignment === "start" ? "bottom" : "top";
if (rects.reference[length] > rects.floating[length]) {
mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
}
return [ mainAlignmentSide, getOppositePlacement(mainAlignmentSide) ];
}
function getExpandedPlacements(placement) {
const oppositePlacement = getOppositePlacement(placement);
return [ getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement) ];
}
function getOppositeAlignmentPlacement(placement) {
return placement.replace(/start|end/g, (alignment => oppositeAlignmentMap[alignment]));
}
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;
case "left":
case "right":
return isStart ? tb : bt;
default:
return [];
}
}
function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
const alignment = getAlignment(placement);
let list = getSideList(getSide(placement), direction === "start", rtl);
if (alignment) {
list = list.map((side => side + "-" + alignment));
if (flipAlignment) {
list = list.concat(list.map(getOppositeAlignmentPlacement));
}
}
return list;
}
function getOppositePlacement(placement) {
return placement.replace(/left|right|bottom|top/g, (side => oppositeSideMap[side]));
}
function expandPaddingObject(padding) {
return {
top: 0,
right: 0,
bottom: 0,
left: 0,
...padding
};
}
function getPaddingObject(padding) {
return typeof padding !== "number" ? expandPaddingObject(padding) : {
top: padding,
right: padding,
bottom: padding,
left: padding
};
}
function rectToClientRect(rect) {
const {x: x, y: y, width: width, height: height} = rect;
return {
width: width,
height: height,
top: y,
left: x,
right: x + width,
bottom: y + height,
x: x,
y: y
};
}
function computeCoordsFromPlacement(_ref, placement, rtl) {
let {reference: reference, floating: 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;
}
const computePosition$1 = async (reference, floating, config) => {
const {placement: placement = "bottom", strategy: strategy = "absolute", middleware: middleware = [], platform: platform} = config;
const validMiddleware = middleware.filter(Boolean);
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
let rects = await platform.getElementRects({
reference: reference,
floating: floating,
strategy: strategy
});
let {x: x, y: y} = computeCoordsFromPlacement(rects, placement, rtl);
let statefulPlacement = placement;
let middlewareData = {};
let resetCount = 0;
for (let i = 0; i < validMiddleware.length; i++) {
const {name: name, fn: fn} = validMiddleware[i];
const {x: nextX, y: nextY, data: data, reset: reset} = await fn({
x: x,
y: y,
initialPlacement: placement,
placement: statefulPlacement,
strategy: strategy,
middlewareData: middlewareData,
rects: rects,
platform: platform,
elements: {
reference: reference,
floating: 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: reference,
floating: floating,
strategy: strategy
}) : reset.rects;
}
({x: x, y: y} = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
}
i = -1;
}
}
return {
x: x,
y: y,
placement: statefulPlacement,
strategy: strategy,
middlewareData: middlewareData
};
};
async function detectOverflow$1(state, options) {
var _await$platform$isEle;
if (options === void 0) {
options = {};
}
const {x: x, y: y, platform: platform, rects: rects, elements: elements, strategy: strategy} = state;
const {boundary: boundary = "clippingAncestors", rootBoundary: rootBoundary = "viewport", elementContext: elementContext = "floating", altBoundary: altBoundary = false, padding: 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: boundary,
rootBoundary: rootBoundary,
strategy: strategy
}));
const rect = elementContext === "floating" ? {
x: x,
y: 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: elements,
rect: rect,
offsetParent: offsetParent,
strategy: 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
};
}
const arrow$1 = options => ({
name: "arrow",
options: options,
async fn(state) {
const {x: x, y: y, placement: placement, rects: rects, platform: platform, elements: elements, middlewareData: middlewareData} = state;
const {element: element, padding: padding = 0} = evaluate(options, state) || {};
if (element == null) {
return {};
}
const paddingObject = getPaddingObject(padding);
const coords = {
x: x,
y: 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;
if (!clientSize || !await (platform.isElement == null ? void 0 : platform.isElement(arrowOffsetParent))) {
clientSize = elements.floating[clientProp] || rects.floating[length];
}
const centerToReference = endDiff / 2 - startDiff / 2;
const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;
const minPadding = min(paddingObject[minProp], largestPossiblePadding);
const maxPadding = min(paddingObject[maxProp], largestPossiblePadding);
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);
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: 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;
}));
}
const autoPlacement$1 = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "autoPlacement",
options: options,
async fn(state) {
var _middlewareData$autoP, _middlewareData$autoP2, _placementsThatFitOnE;
const {rects: rects, middlewareData: middlewareData, placement: placement, platform: platform, elements: elements} = state;
const {crossAxis: crossAxis = false, alignment: alignment, allowedPlacements: allowedPlacements = placements, autoAlignment: autoAlignment = true, ...detectOverflowOptions} = evaluate(options, state);
const placements$1 = alignment !== undefined || allowedPlacements === placements ? getPlacementList(alignment || null, autoAlignment, allowedPlacements) : allowedPlacements;
const overflow = await detectOverflow$1(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)));
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];
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 ? d.overflows.slice(0, 2).reduce(((acc, v) => acc + v), 0) : d.overflows[0], d.overflows ];
})).sort(((a, b) => a[1] - b[1]));
const placementsThatFitOnEachSide = placementsSortedByMostSpace.filter((d => d[2].slice(0, 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 {};
}
};
};
const flip = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "flip",
options: options,
async fn(state) {
var _middlewareData$arrow, _middlewareData$flip;
const {placement: placement, middlewareData: middlewareData, rects: rects, initialPlacement: initialPlacement, platform: platform, elements: elements} = state;
const {mainAxis: checkMainAxis = true, crossAxis: checkCrossAxis = true, fallbackPlacements: specifiedFallbackPlacements, fallbackStrategy: fallbackStrategy = "bestFit", fallbackAxisSideDirection: fallbackAxisSideDirection = "none", flipAlignment: flipAlignment = true, ...detectOverflowOptions} = evaluate(options, state);
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$1(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: placement,
overflows: overflows
} ];
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) {
return {
data: {
index: nextIndex,
overflows: overflowsData
},
reset: {
placement: nextPlacement
}
};
}
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;
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 || 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));
}
const hide = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "hide",
options: options,
async fn(state) {
const {rects: rects} = state;
const {strategy: strategy = "referenceHidden", ...detectOverflowOptions} = evaluate(options, state);
switch (strategy) {
case "referenceHidden":
{
const overflow = await detectOverflow$1(state, {
...detectOverflowOptions,
elementContext: "reference"
});
const offsets = getSideOffsets(overflow, rects.reference);
return {
data: {
referenceHiddenOffsets: offsets,
referenceHidden: isAnySideFullyClipped(offsets)
}
};
}
case "escaped":
{
const overflow = await detectOverflow$1(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))));
}
const inline = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "inline",
options: options,
async fn(state) {
const {placement: placement, elements: elements, rects: rects, platform: platform, strategy: strategy} = state;
const {padding: padding = 2, x: x, y: 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() {
if (clientRects.length === 2 && clientRects[0].left > clientRects[1].right && x != null && y != null) {
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;
}
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: top,
bottom: bottom,
left: left,
right: right,
width: width,
height: 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: top,
bottom: bottom,
left: left,
right: right,
width: width,
height: height,
x: left,
y: top
};
}
return fallback;
}
const resetRects = await platform.getElementRects({
reference: {
getBoundingClientRect: getBoundingClientRect
},
floating: elements.floating,
strategy: 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 {};
}
};
};
async function convertValueToCoords(state, options) {
const {placement: placement, platform: platform, elements: 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);
let {mainAxis: mainAxis, crossAxis: crossAxis, alignmentAxis: 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
};
}
const offset$1 = function(options) {
if (options === void 0) {
options = 0;
}
return {
name: "offset",
options: options,
async fn(state) {
var _middlewareData$offse, _middlewareData$arrow;
const {x: x, y: y, placement: placement, middlewareData: middlewareData} = state;
const diffCoords = await convertValueToCoords(state, options);
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: placement
}
};
}
};
};
const shift = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "shift",
options: options,
async fn(state) {
const {x: x, y: y, placement: placement} = state;
const {mainAxis: checkMainAxis = true, crossAxis: checkCrossAxis = false, limiter: limiter = {
fn: _ref => {
let {x: x, y: y} = _ref;
return {
x: x,
y: y
};
}
}, ...detectOverflowOptions} = evaluate(options, state);
const coords = {
x: x,
y: y
};
const overflow = await detectOverflow$1(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
}
}
};
}
};
};
const limitShift = function(options) {
if (options === void 0) {
options = {};
}
return {
options: options,
fn(state) {
const {x: x, y: y, placement: placement, rects: rects, middlewareData: middlewareData} = state;
const {offset: offset = 0, mainAxis: checkMainAxis = true, crossAxis: checkCrossAxis = true} = evaluate(options, state);
const coords = {
x: x,
y: 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
};
}
};
};
const size = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "size",
options: options,
async fn(state) {
var _state$middlewareData, _state$middlewareData2;
const {placement: placement, rects: rects, platform: platform, elements: elements} = state;
const {apply: apply = () => {}, ...detectOverflowOptions} = evaluate(options, state);
const overflow = await detectOverflow$1(state, detectOverflowOptions);
const side = getSide(placement);
const alignment = getAlignment(placement);
const isYAxis = getSideAxis(placement) === "y";
const {width: width, height: 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: availableWidth,
availableHeight: availableHeight
});
const nextDimensions = await platform.getDimensions(elements.floating);
if (width !== nextDimensions.width || height !== nextDimensions.height) {
return {
reset: {
rects: true
}
};
}
return {};
}
};
};
function hasWindow() {
return typeof window !== "undefined";
}
function getNodeName(node) {
if (isNode(node)) {
return (node.nodeName || "").toLowerCase();
}
return "#document";
}
function getWindow(node) {
var _node$ownerDocument;
return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
}
function getDocumentElement(node) {
var _ref;
return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
}
function isNode(value) {
if (!hasWindow()) {
return false;
}
return value instanceof Node || value instanceof getWindow(value).Node;
}
function isElement(value) {
if (!hasWindow()) {
return false;
}
return value instanceof Element || value instanceof getWindow(value).Element;
}
function isHTMLElement(value) {
if (!hasWindow()) {
return false;
}
return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
}
function isShadowRoot(value) {
if (!hasWindow() || typeof ShadowRoot === "undefined") {
return false;
}
return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
}
function isOverflowElement(element) {
const {overflow: overflow, overflowX: overflowX, overflowY: overflowY, display: display} = getComputedStyle$1(element);
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && ![ "inline", "contents" ].includes(display);
}
function isTableElement(element) {
return [ "table", "td", "th" ].includes(getNodeName(element));
}
function isTopLayer(element) {
return [ ":popover-open", ":modal" ].some((selector => {
try {
return element.matches(selector);
} catch (e) {
return false;
}
}));
}
function isContainingBlock(elementOrCss) {
const webkit = isWebKit();
const css = isElement(elementOrCss) ? getComputedStyle$1(elementOrCss) : elementOrCss;
return css.transform !== "none" || css.perspective !== "none" || (css.containerType ? css.containerType !== "normal" : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== "none" : false) || !webkit && (css.filter ? css.filter !== "none" : false) || [ "transform", "perspective", "filter" ].some((value => (css.willChange || "").includes(value))) || [ "paint", "layout", "strict", "content" ].some((value => (css.contain || "").includes(value)));
}
function getContainingBlock(element) {
let currentNode = getParentNode(element);
while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
if (isContainingBlock(currentNode)) {
return currentNode;
} else if (isTopLayer(currentNode)) {
return null;
}
currentNode = getParentNode(currentNode);
}
return null;
}
function isWebKit() {
if (typeof CSS === "undefined" || !CSS.supports) return false;
return CSS.supports("-webkit-backdrop-filter", "none");
}
function isLastTraversableNode(node) {
return [ "html", "body", "#document" ].includes(getNodeName(node));
}
function getComputedStyle$1(element) {
return getWindow(element).getComputedStyle(element);
}
function getNodeScroll(element) {
if (isElement(element)) {
return {
scrollLeft: element.scrollLeft,
scrollTop: element.scrollTop
};
}
return {
scrollLeft: element.scrollX,
scrollTop: element.scrollY
};
}
function getParentNode(node) {
if (getNodeName(node) === "html") {
return node;
}
const result = node.assignedSlot || node.parentNode || isShadowRoot(node) && node.host || getDocumentElement(node);
return isShadowRoot(result) ? result.host : result;
}
function getNearestOverflowAncestor(node) {
const parentNode = getParentNode(node);
if (isLastTraversableNode(parentNode)) {
return node.ownerDocument ? node.ownerDocument.body : node.body;
}
if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
return parentNode;
}
return getNearestOverflowAncestor(parentNode);
}
function getOverflowAncestors(node, list, traverseIframes) {
var _node$ownerDocument2;
if (list === void 0) {
list = [];
}
if (traverseIframes === void 0) {
traverseIframes = true;
}
const scrollableAncestor = getNearestOverflowAncestor(node);
const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
const win = getWindow(scrollableAncestor);
if (isBody) {
const frameElement = getFrameElement(win);
return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
}
return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
}
function getFrameElement(win) {
return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
}
function getCssDimensions(element) {
const css = getComputedStyle$1(element);
let width = parseFloat(css.width) || 0;
let height = parseFloat(css.height) || 0;
const hasOffset = isHTMLElement(element);
const offsetWidth = hasOffset ? element.offsetWidth : width;
const offsetHeight = hasOffset ? element.offsetHeight : height;
const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight;
if (shouldFallback) {
width = offsetWidth;
height = offsetHeight;
}
return {
width: width,
height: height,
$: shouldFallback
};
}
function unwrapElement(element) {
return !isElement(element) ? element.contextElement : element;
}
function getScale(element) {
const domElement = unwrapElement(element);
if (!isHTMLElement(domElement)) {
return createCoords(1);
}
const rect = domElement.getBoundingClientRect();
const {width: width, height: height, $: $} = getCssDimensions(domElement);
let x = ($ ? round(rect.width) : rect.width) / width;
let y = ($ ? round(rect.height) : rect.height) / height;
if (!x || !Number.isFinite(x)) {
x = 1;
}
if (!y || !Number.isFinite(y)) {
y = 1;
}
return {
x: x,
y: y
};
}
const noOffsets = createCoords(0);
function getVisualOffsets(element) {
const win = getWindow(element);
if (!isWebKit() || !win.visualViewport) {
return noOffsets;
}
return {
x: win.visualViewport.offsetLeft,
y: win.visualViewport.offsetTop
};
}
function shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) {
if (isFixed === void 0) {
isFixed = false;
}
if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow(element)) {
return false;
}
return isFixed;
}
function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) {
if (includeScale === void 0) {
includeScale = false;
}
if (isFixedStrategy === void 0) {
isFixedStrategy = false;
}
const clientRect = element.getBoundingClientRect();
const domElement = unwrapElement(element);
let scale = createCoords(1);
if (includeScale) {
if (offsetParent) {
if (isElement(offsetParent)) {
scale = getScale(offsetParent);
}
} else {
scale = getScale(element);
}
}
const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0);
let x = (clientRect.left + visualOffsets.x) / scale.x;
let y = (clientRect.top + visualOffsets.y) / scale.y;
let width = clientRect.width / scale.x;
let height = clientRect.height / scale.y;
if (domElement) {
const win = getWindow(domElement);
const offsetWin = offsetParent && isElement(offsetParent) ? getWindow(offsetParent) : offsetParent;
let currentWin = win;
let currentIFrame = getFrameElement(currentWin);
while (currentIFrame && offsetParent && offsetWin !== currentWin) {
const iframeScale = getScale(currentIFrame);
const iframeRect = currentIFrame.getBoundingClientRect();
const css = getComputedStyle$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;
y *= iframeScale.y;
width *= iframeScale.x;
height *= iframeScale.y;
x += left;
y += top;
currentWin = getWindow(currentIFrame);
currentIFrame = getFrameElement(currentWin);
}
}
return rectToClientRect({
width: width,
height: height,
x: x,
y: y
});
}
function getWindowScrollBarX(element, rect) {
const leftScroll = getNodeScroll(element).scrollLeft;
if (!rect) {
return getBoundingClientRect(getDocumentElement(element)).left + leftScroll;
}
return rect.left + leftScroll;
}
function getHTMLOffset(documentElement, scroll, ignoreScrollbarX) {
if (ignoreScrollbarX === void 0) {
ignoreScrollbarX = false;
}
const htmlRect = documentElement.getBoundingClientRect();
const x = htmlRect.left + scroll.scrollLeft - (ignoreScrollbarX ? 0 : getWindowScrollBarX(documentElement, htmlRect));
const y = htmlRect.top + scroll.scrollTop;
return {
x: x,
y: y
};
}
function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
let {elements: elements, rect: rect, offsetParent: offsetParent, strategy: strategy} = _ref;
const isFixed = strategy === "fixed";
const documentElement = getDocumentElement(offsetParent);
const topLayer = elements ? isTopLayer(elements.floating) : false;
if (offsetParent === documentElement || topLayer && isFixed) {
return rect;
}
let scroll = {
scrollLeft: 0,
scrollTop: 0
};
let scale = createCoords(1);
const offsets = createCoords(0);
const isOffsetParentAnElement = isHTMLElement(offsetParent);
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) {
scroll = getNodeScroll(offsetParent);
}
if (isHTMLElement(offsetParent)) {
const offsetRect = getBoundingClientRect(offsetParent);
scale = getScale(offsetParent);
offsets.x = offsetRect.x + offsetParent.clientLeft;
offsets.y = offsetRect.y + offsetParent.clientTop;
}
}
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll, true) : createCoords(0);
return {
width: rect.width * scale.x,
height: rect.height * scale.y,
x: rect.x * scale.x - scroll.scrollLef