mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Refactor popover engine to use Floating UI
This commit is contained in:
1 parent
3b53cfd683
commit
43a75e86c8
8 files changed
+194
-232
No files matched your search
@@ -76,6 +76,18 @@ Pass `document`, `placement`, and other floating-ui options through the third
|
||||
argument. The helper exposes `open()`, `close()`, `toggle()`, `isOpen()`, and
|
||||
`destroy()` for lifecycle control.
|
||||
|
||||
### Floating UI dependency
|
||||
|
||||
The shared popover engine standardizes on
|
||||
[`@floating-ui/dom`](https://floating-ui.com/) for positioning. The module is
|
||||
vendored to `vendor/floating-ui.dom.bundle.min.js` by
|
||||
`npm run build:beacon`, which bundles dependencies and copies the upstream
|
||||
license alongside `nostr-tools`. Run that build whenever you bump Floating UI so
|
||||
the checked-in vendor artifact stays in sync. New overlays should lean on the
|
||||
engine rather than re-implementing manual gap, flip, or viewport clamp math—the
|
||||
middleware layer already applies the configured gap and viewport padding via
|
||||
`offset()`, `flip()`, and `shift()` helpers.
|
||||
|
||||
## Tailwind overlay classes
|
||||
|
||||
Tailwind ships token-backed overlay helpers that keep surfaces aligned with the
|
||||
|
||||
+94
-231
@@ -5,6 +5,14 @@ import {
|
||||
readDesignToken,
|
||||
} from "../../designSystem/metrics.js";
|
||||
import { ensureOverlayRoot } from "./overlayRoot.js";
|
||||
import {
|
||||
arrow as arrowMiddleware,
|
||||
autoUpdate,
|
||||
computePosition,
|
||||
flip,
|
||||
offset,
|
||||
shift,
|
||||
} from "../../../vendor/floating-ui.dom.bundle.min.js";
|
||||
|
||||
const DEFAULT_PLACEMENT = "bottom-start";
|
||||
const DEFAULT_STRATEGY = "fixed";
|
||||
@@ -107,61 +115,56 @@ function resolveArrow(option, panel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function applyArrowStyles({
|
||||
arrowElement,
|
||||
side,
|
||||
panelLeft,
|
||||
panelTop,
|
||||
panelWidth,
|
||||
panelHeight,
|
||||
anchorRect,
|
||||
}) {
|
||||
if (!arrowElement || !side || !anchorRect) {
|
||||
function applyArrowStyles({ arrowElement, placement, middlewareData }) {
|
||||
if (!arrowElement || typeof placement !== "string") {
|
||||
return;
|
||||
}
|
||||
|
||||
const arrowRect =
|
||||
typeof arrowElement.getBoundingClientRect === "function"
|
||||
? arrowElement.getBoundingClientRect()
|
||||
: null;
|
||||
const arrowWidth = arrowRect?.width ?? arrowElement.offsetWidth ?? 0;
|
||||
const arrowHeight = arrowRect?.height ?? arrowElement.offsetHeight ?? 0;
|
||||
|
||||
const anchorCenterX = anchorRect.left + anchorRect.width / 2;
|
||||
const anchorCenterY = anchorRect.top + anchorRect.height / 2;
|
||||
const basePlacement = placement.split("-")[0];
|
||||
const arrowData = middlewareData?.arrow || null;
|
||||
|
||||
arrowElement.style.left = "";
|
||||
arrowElement.style.right = "";
|
||||
arrowElement.style.top = "";
|
||||
arrowElement.style.bottom = "";
|
||||
|
||||
if (side === "top" || side === "bottom") {
|
||||
let arrowLeft = anchorCenterX - panelLeft - arrowWidth / 2;
|
||||
arrowLeft = Math.min(
|
||||
Math.max(arrowLeft, 0),
|
||||
Math.max(panelWidth - arrowWidth, 0),
|
||||
);
|
||||
arrowElement.style.left = `${Math.round(arrowLeft)}px`;
|
||||
if (side === "bottom") {
|
||||
arrowElement.style.top = `${-Math.round(arrowHeight)}px`;
|
||||
} else {
|
||||
arrowElement.style.bottom = `${-Math.round(arrowHeight)}px`;
|
||||
}
|
||||
} else if (side === "left" || side === "right") {
|
||||
let arrowTop = anchorCenterY - panelTop - arrowHeight / 2;
|
||||
arrowTop = Math.min(
|
||||
Math.max(arrowTop, 0),
|
||||
Math.max(panelHeight - arrowHeight, 0),
|
||||
);
|
||||
arrowElement.style.top = `${Math.round(arrowTop)}px`;
|
||||
if (side === "right") {
|
||||
arrowElement.style.left = `${-Math.round(arrowWidth)}px`;
|
||||
} else {
|
||||
arrowElement.style.right = `${-Math.round(arrowWidth)}px`;
|
||||
}
|
||||
if (!arrowData || !basePlacement) {
|
||||
delete arrowElement.dataset.popoverArrowSide;
|
||||
return;
|
||||
}
|
||||
|
||||
arrowElement.dataset.popoverArrowSide = side;
|
||||
const staticSideMap = {
|
||||
top: "bottom",
|
||||
right: "left",
|
||||
bottom: "top",
|
||||
left: "right",
|
||||
};
|
||||
|
||||
if (Number.isFinite(arrowData.x)) {
|
||||
arrowElement.style.left = `${Math.round(arrowData.x)}px`;
|
||||
}
|
||||
|
||||
if (Number.isFinite(arrowData.y)) {
|
||||
arrowElement.style.top = `${Math.round(arrowData.y)}px`;
|
||||
}
|
||||
|
||||
const staticSide = staticSideMap[basePlacement] || null;
|
||||
|
||||
if (staticSide) {
|
||||
const arrowRect =
|
||||
typeof arrowElement.getBoundingClientRect === "function"
|
||||
? arrowElement.getBoundingClientRect()
|
||||
: null;
|
||||
const arrowWidth = arrowRect?.width ?? arrowElement.offsetWidth ?? 0;
|
||||
const arrowHeight = arrowRect?.height ?? arrowElement.offsetHeight ?? 0;
|
||||
const offsetValue =
|
||||
basePlacement === "top" || basePlacement === "bottom"
|
||||
? arrowHeight
|
||||
: arrowWidth;
|
||||
arrowElement.style[staticSide] = `${-Math.round(offsetValue)}px`;
|
||||
}
|
||||
|
||||
arrowElement.dataset.popoverArrowSide = basePlacement;
|
||||
}
|
||||
|
||||
function containsTarget(root, target) {
|
||||
@@ -181,85 +184,6 @@ function setExpandedAttribute(trigger, value) {
|
||||
trigger.setAttribute("aria-expanded", value ? "true" : "false");
|
||||
}
|
||||
|
||||
function createAutoUpdate({ documentRef, anchor, panel, update }) {
|
||||
if (!documentRef || !anchor || !panel || typeof update !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cleanupFns = [];
|
||||
const safeUpdate = () => {
|
||||
try {
|
||||
const result = update();
|
||||
if (result && typeof result.then === "function") {
|
||||
result.catch((error) => {
|
||||
logger.dev.warn("[popover] auto-update failed", error);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.dev.warn("[popover] auto-update failed", error);
|
||||
}
|
||||
};
|
||||
|
||||
const view = documentRef.defaultView || globalThis;
|
||||
if (view && typeof view.addEventListener === "function") {
|
||||
const resizeHandler = () => safeUpdate();
|
||||
view.addEventListener("resize", resizeHandler);
|
||||
cleanupFns.push(() => view.removeEventListener("resize", resizeHandler));
|
||||
|
||||
const scrollHandler = () => safeUpdate();
|
||||
view.addEventListener("scroll", scrollHandler, true);
|
||||
cleanupFns.push(() => view.removeEventListener("scroll", scrollHandler, true));
|
||||
}
|
||||
|
||||
const scrollTarget = documentRef.scrollingElement || documentRef;
|
||||
if (scrollTarget && typeof scrollTarget.addEventListener === "function") {
|
||||
const docScrollHandler = () => safeUpdate();
|
||||
scrollTarget.addEventListener("scroll", docScrollHandler, true);
|
||||
cleanupFns.push(() =>
|
||||
scrollTarget.removeEventListener("scroll", docScrollHandler, true),
|
||||
);
|
||||
}
|
||||
|
||||
const observers = [];
|
||||
if (typeof ResizeObserver === "function") {
|
||||
try {
|
||||
const anchorObserver = new ResizeObserver(safeUpdate);
|
||||
anchorObserver.observe(anchor);
|
||||
observers.push(anchorObserver);
|
||||
} catch (error) {
|
||||
logger.dev.warn("[popover] anchor resize observer failed", error);
|
||||
}
|
||||
|
||||
if (panel !== anchor) {
|
||||
try {
|
||||
const panelObserver = new ResizeObserver(safeUpdate);
|
||||
panelObserver.observe(panel);
|
||||
observers.push(panelObserver);
|
||||
} catch (error) {
|
||||
logger.dev.warn("[popover] panel resize observer failed", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
cleanupFns.forEach((cleanup) => {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
logger.dev.warn("[popover] auto-update cleanup failed", error);
|
||||
}
|
||||
});
|
||||
|
||||
observers.forEach((observer) => {
|
||||
try {
|
||||
observer.disconnect();
|
||||
} catch (error) {
|
||||
logger.dev.warn("[popover] observer disconnect failed", error);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function createPopover(trigger, render, options = {}) {
|
||||
const anchor = isElement(trigger) ? trigger : null;
|
||||
const documentRef = resolveDocument(anchor, options.document);
|
||||
@@ -714,124 +638,56 @@ export function createPopover(trigger, render, options = {}) {
|
||||
}
|
||||
|
||||
async function updatePosition() {
|
||||
if (!anchor || !panel || !documentRef) {
|
||||
if (!anchor || !panel) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const anchorRect =
|
||||
typeof anchor.getBoundingClientRect === "function"
|
||||
? anchor.getBoundingClientRect()
|
||||
: null;
|
||||
if (!anchorRect) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = documentRef.defaultView || globalThis;
|
||||
const docEl = documentRef.documentElement || null;
|
||||
const viewportWidth =
|
||||
docEl?.clientWidth ?? view?.innerWidth ?? panel.offsetWidth ?? 0;
|
||||
const viewportHeight =
|
||||
docEl?.clientHeight ?? view?.innerHeight ?? panel.offsetHeight ?? 0;
|
||||
|
||||
const panelRect =
|
||||
typeof panel.getBoundingClientRect === "function"
|
||||
? panel.getBoundingClientRect()
|
||||
: null;
|
||||
const panelWidth = panelRect?.width ?? panel.offsetWidth ?? 0;
|
||||
const panelHeight = panelRect?.height ?? panel.offsetHeight ?? 0;
|
||||
|
||||
let [side, alignment = "start"] = placement.split("-");
|
||||
if (!side || !["top", "bottom", "left", "right"].includes(side)) {
|
||||
side = "bottom";
|
||||
}
|
||||
if (!["start", "end", "center"].includes(alignment)) {
|
||||
alignment = "start";
|
||||
}
|
||||
|
||||
const effectiveGap = Number.isFinite(gap) ? gap : 0;
|
||||
const safePadding = Number.isFinite(viewportPadding) ? viewportPadding : 0;
|
||||
const middleware = [
|
||||
offset(effectiveGap),
|
||||
flip({ padding: safePadding }),
|
||||
shift({ padding: safePadding }),
|
||||
];
|
||||
|
||||
function clamp(value, min, max, fallback) {
|
||||
if (!Number.isFinite(value)) {
|
||||
return fallback ?? min;
|
||||
}
|
||||
if (min > max) {
|
||||
return fallback ?? (min + max) / 2;
|
||||
}
|
||||
return Math.min(Math.max(value, min), max);
|
||||
if (arrowElement) {
|
||||
middleware.push(
|
||||
arrowMiddleware({
|
||||
element: arrowElement,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (side === "bottom") {
|
||||
const fitsBelow =
|
||||
anchorRect.bottom + effectiveGap + panelHeight <=
|
||||
viewportHeight - safePadding;
|
||||
const fitsAbove =
|
||||
anchorRect.top - effectiveGap - panelHeight >= safePadding;
|
||||
if (!fitsBelow && fitsAbove) {
|
||||
side = "top";
|
||||
}
|
||||
} else if (side === "top") {
|
||||
const fitsAbove =
|
||||
anchorRect.top - effectiveGap - panelHeight >= safePadding;
|
||||
const fitsBelow =
|
||||
anchorRect.bottom + effectiveGap + panelHeight <=
|
||||
viewportHeight - safePadding;
|
||||
if (!fitsAbove && fitsBelow) {
|
||||
side = "bottom";
|
||||
}
|
||||
}
|
||||
const {
|
||||
x,
|
||||
y,
|
||||
placement: resolvedPlacement,
|
||||
middlewareData,
|
||||
strategy: resolvedStrategy,
|
||||
} = await computePosition(anchor, panel, {
|
||||
placement,
|
||||
strategy,
|
||||
middleware,
|
||||
});
|
||||
|
||||
let top = 0;
|
||||
let left = 0;
|
||||
const nextX = Number.isFinite(x) ? x : 0;
|
||||
const nextY = Number.isFinite(y) ? y : 0;
|
||||
const finalPlacement =
|
||||
typeof resolvedPlacement === "string" && resolvedPlacement
|
||||
? resolvedPlacement
|
||||
: placement;
|
||||
|
||||
if (side === "top") {
|
||||
top = anchorRect.top - panelHeight - effectiveGap;
|
||||
} else if (side === "bottom") {
|
||||
top = anchorRect.bottom + effectiveGap;
|
||||
} else if (side === "left") {
|
||||
top = anchorRect.top + anchorRect.height / 2 - panelHeight / 2;
|
||||
} else if (side === "right") {
|
||||
top = anchorRect.top + anchorRect.height / 2 - panelHeight / 2;
|
||||
}
|
||||
|
||||
if (side === "left") {
|
||||
left = anchorRect.left - panelWidth - effectiveGap;
|
||||
} else if (side === "right") {
|
||||
left = anchorRect.right + effectiveGap;
|
||||
} else if (alignment === "end") {
|
||||
left = anchorRect.right - panelWidth;
|
||||
} else if (alignment === "center") {
|
||||
left = anchorRect.left + anchorRect.width / 2 - panelWidth / 2;
|
||||
} else {
|
||||
left = anchorRect.left;
|
||||
}
|
||||
|
||||
const minTop = safePadding;
|
||||
const maxTop = viewportHeight - safePadding - panelHeight;
|
||||
const minLeft = safePadding;
|
||||
const maxLeft = viewportWidth - safePadding - panelWidth;
|
||||
|
||||
const fallbackTop = viewportHeight / 2 - panelHeight / 2;
|
||||
const fallbackLeft = viewportWidth / 2 - panelWidth / 2;
|
||||
|
||||
top = clamp(top, minTop, maxTop, fallbackTop);
|
||||
left = clamp(left, minLeft, maxLeft, fallbackLeft);
|
||||
|
||||
panel.style.position = strategy;
|
||||
panel.style.left = `${Math.round(left)}px`;
|
||||
panel.style.top = `${Math.round(top)}px`;
|
||||
panel.dataset.popoverPlacement = `${side}-${alignment}`;
|
||||
panel.style.position = resolvedStrategy || strategy;
|
||||
panel.style.left = `${Math.round(nextX)}px`;
|
||||
panel.style.top = `${Math.round(nextY)}px`;
|
||||
panel.dataset.popoverPlacement = finalPlacement;
|
||||
|
||||
if (arrowElement) {
|
||||
applyArrowStyles({
|
||||
arrowElement,
|
||||
side,
|
||||
panelLeft: left,
|
||||
panelTop: top,
|
||||
panelWidth,
|
||||
panelHeight,
|
||||
anchorRect,
|
||||
placement: finalPlacement,
|
||||
middlewareData,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -909,12 +765,19 @@ export function createPopover(trigger, render, options = {}) {
|
||||
autoUpdateCleanup = null;
|
||||
}
|
||||
|
||||
autoUpdateCleanup = createAutoUpdate({
|
||||
documentRef,
|
||||
autoUpdateCleanup = autoUpdate(
|
||||
anchor,
|
||||
panel: panelElement,
|
||||
update: () => updatePosition(),
|
||||
});
|
||||
panelElement,
|
||||
() => {
|
||||
void updatePosition();
|
||||
},
|
||||
{
|
||||
ancestorScroll: true,
|
||||
ancestorResize: true,
|
||||
elementResize: true,
|
||||
layoutShift: true,
|
||||
},
|
||||
);
|
||||
|
||||
await updatePosition();
|
||||
|
||||
|
||||
Generated
+26
@@ -9,6 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.4",
|
||||
"path": "^0.12.7",
|
||||
"webtorrent": "^1.9.7"
|
||||
},
|
||||
@@ -708,6 +709,31 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
|
||||
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/utils": "^0.2.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
|
||||
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.7.3",
|
||||
"@floating-ui/utils": "^0.2.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/utils": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
|
||||
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
},
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.4",
|
||||
"path": "^0.12.7",
|
||||
"webtorrent": "^1.9.7"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { build } from "esbuild";
|
||||
import { mkdir } from "node:fs/promises";
|
||||
import { copyFile, mkdir } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -11,8 +12,23 @@ const repoRoot = path.resolve(__dirname, "..");
|
||||
const entryPoint = path.join(repoRoot, "torrent/src/beacon-vendor.js");
|
||||
const outDir = path.join(repoRoot, "torrent/dist");
|
||||
const outFile = path.join(outDir, "beacon.js");
|
||||
const vendorDir = path.join(repoRoot, "vendor");
|
||||
const vendorOutFile = path.join(vendorDir, "floating-ui.dom.bundle.min.js");
|
||||
const vendorLicenseFile = path.join(vendorDir, "floating-ui.LICENSE");
|
||||
const floatingUiEntry = path.join(
|
||||
repoRoot,
|
||||
"scripts/vendor/floating-ui-dom-entry.mjs",
|
||||
);
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const floatingUiPackageJson = require.resolve("@floating-ui/dom/package.json");
|
||||
const floatingUiLicense = path.join(
|
||||
path.dirname(floatingUiPackageJson),
|
||||
"LICENSE",
|
||||
);
|
||||
|
||||
await mkdir(outDir, { recursive: true });
|
||||
await mkdir(vendorDir, { recursive: true });
|
||||
|
||||
await build({
|
||||
bundle: true,
|
||||
@@ -34,3 +50,18 @@ await build({
|
||||
},
|
||||
logLevel: "info",
|
||||
});
|
||||
|
||||
await build({
|
||||
bundle: true,
|
||||
entryPoints: [floatingUiEntry],
|
||||
outfile: vendorOutFile,
|
||||
format: "esm",
|
||||
splitting: false,
|
||||
platform: "browser",
|
||||
target: ["es2020"],
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
logLevel: "info",
|
||||
});
|
||||
|
||||
await copyFile(floatingUiLicense, vendorLicenseFile);
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
export {
|
||||
arrow,
|
||||
autoUpdate,
|
||||
computePosition,
|
||||
flip,
|
||||
offset,
|
||||
shift,
|
||||
} from "@floating-ui/dom";
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-present Floating UI contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
var H=Math.min,B=Math.max,ot=Math.round,it=Math.floor,L=t=>({x:t,y:t}),qt={left:"right",right:"left",bottom:"top",top:"bottom"},Ut={start:"end",end:"start"};function lt(t,e,n){return B(t,H(e,n))}function U(t,e){return typeof t=="function"?t(e):t}function V(t){return t.split("-")[0]}function K(t){return t.split("-")[1]}function pt(t){return t==="x"?"y":"x"}function at(t){return t==="y"?"height":"width"}var Kt=new Set(["top","bottom"]);function W(t){return Kt.has(V(t))?"y":"x"}function ft(t){return pt(W(t))}function Ot(t,e,n){n===void 0&&(n=!1);let o=K(t),i=ft(t),r=at(i),s=i==="x"?o===(n?"end":"start")?"right":"left":o==="start"?"bottom":"top";return e.reference[r]>e.floating[r]&&(s=nt(s)),[s,nt(s)]}function Rt(t){let e=nt(t);return[ct(t),e,ct(e)]}function ct(t){return t.replace(/start|end/g,e=>Ut[e])}var bt=["left","right"],At=["right","left"],Gt=["top","bottom"],Jt=["bottom","top"];function Qt(t,e,n){switch(t){case"top":case"bottom":return n?e?At:bt:e?bt:At;case"left":case"right":return e?Gt:Jt;default:return[]}}function St(t,e,n,o){let i=K(t),r=Qt(V(t),n==="start",o);return i&&(r=r.map(s=>s+"-"+i),e&&(r=r.concat(r.map(ct)))),r}function nt(t){return t.replace(/left|right|bottom|top/g,e=>qt[e])}function Zt(t){return{top:0,right:0,bottom:0,left:0,...t}}function wt(t){return typeof t!="number"?Zt(t):{top:t,right:t,bottom:t,left:t}}function X(t){let{x:e,y:n,width:o,height:i}=t;return{width:o,height:i,top:n,left:e,right:e+o,bottom:n+i,x:e,y:n}}function Ct(t,e,n){let{reference:o,floating:i}=t,r=W(e),s=ft(e),c=at(s),a=V(e),l=r==="y",d=o.x+o.width/2-i.width/2,u=o.y+o.height/2-i.height/2,g=o[c]/2-i[c]/2,f;switch(a){case"top":f={x:d,y:o.y-i.height};break;case"bottom":f={x:d,y:o.y+o.height};break;case"right":f={x:o.x+o.width,y:u};break;case"left":f={x:o.x-i.width,y:u};break;default:f={x:o.x,y:o.y}}switch(K(e)){case"start":f[s]-=g*(n&&l?-1:1);break;case"end":f[s]+=g*(n&&l?-1:1);break}return f}var Pt=async(t,e,n)=>{let{placement:o="bottom",strategy:i="absolute",middleware:r=[],platform:s}=n,c=r.filter(Boolean),a=await(s.isRTL==null?void 0:s.isRTL(e)),l=await s.getElementRects({reference:t,floating:e,strategy:i}),{x:d,y:u}=Ct(l,o,a),g=o,f={},m=0;for(let h=0;h<c.length;h++){let{name:w,fn:p}=c[h],{x,y,data:b,reset:v}=await p({x:d,y:u,initialPlacement:o,placement:g,strategy:i,middlewareData:f,rects:l,platform:s,elements:{reference:t,floating:e}});d=x??d,u=y??u,f={...f,[w]:{...f[w],...b}},v&&m<=50&&(m++,typeof v=="object"&&(v.placement&&(g=v.placement),v.rects&&(l=v.rects===!0?await s.getElementRects({reference:t,floating:e,strategy:i}):v.rects),{x:d,y:u}=Ct(l,g,a)),h=-1)}return{x:d,y:u,placement:g,strategy:i,middlewareData:f}};async function xt(t,e){var n;e===void 0&&(e={});let{x:o,y:i,platform:r,rects:s,elements:c,strategy:a}=t,{boundary:l="clippingAncestors",rootBoundary:d="viewport",elementContext:u="floating",altBoundary:g=!1,padding:f=0}=U(e,t),m=wt(f),w=c[g?u==="floating"?"reference":"floating":u],p=X(await r.getClippingRect({element:(n=await(r.isElement==null?void 0:r.isElement(w)))==null||n?w:w.contextElement||await(r.getDocumentElement==null?void 0:r.getDocumentElement(c.floating)),boundary:l,rootBoundary:d,strategy:a})),x=u==="floating"?{x:o,y:i,width:s.floating.width,height:s.floating.height}:s.reference,y=await(r.getOffsetParent==null?void 0:r.getOffsetParent(c.floating)),b=await(r.isElement==null?void 0:r.isElement(y))?await(r.getScale==null?void 0:r.getScale(y))||{x:1,y:1}:{x:1,y:1},v=X(r.convertOffsetParentRelativeRectToViewportRelativeRect?await r.convertOffsetParentRelativeRectToViewportRelativeRect({elements:c,rect:x,offsetParent:y,strategy:a}):x);return{top:(p.top-v.top+m.top)/b.y,bottom:(v.bottom-p.bottom+m.bottom)/b.y,left:(p.left-v.left+m.left)/b.x,right:(v.right-p.right+m.right)/b.x}}var Tt=t=>({name:"arrow",options:t,async fn(e){let{x:n,y:o,placement:i,rects:r,platform:s,elements:c,middlewareData:a}=e,{element:l,padding:d=0}=U(t,e)||{};if(l==null)return{};let u=wt(d),g={x:n,y:o},f=ft(i),m=at(f),h=await s.getDimensions(l),w=f==="y",p=w?"top":"left",x=w?"bottom":"right",y=w?"clientHeight":"clientWidth",b=r.reference[m]+r.reference[f]-g[f]-r.floating[m],v=g[f]-r.reference[f],M=await(s.getOffsetParent==null?void 0:s.getOffsetParent(l)),R=M?M[y]:0;(!R||!await(s.isElement==null?void 0:s.isElement(M)))&&(R=c.floating[y]||r.floating[m]);let Z=b/2-v/2,_=R/2-h[m]/2-1,F=H(u[p],_),tt=H(u[x],_),z=F,et=R-h[m]-tt,A=R/2-h[m]/2+Z,I=lt(z,A,et),k=!a.arrow&&K(i)!=null&&A!==I&&r.reference[m]/2-(A<z?F:tt)-h[m]/2<0,P=k?A<z?A-z:A-et:0;return{[f]:g[f]+P,data:{[f]:I,centerOffset:A-I-P,...k&&{alignmentOffset:P}},reset:k}}});var Lt=function(t){return t===void 0&&(t={}),{name:"flip",options:t,async fn(e){var n,o;let{placement:i,middlewareData:r,rects:s,initialPlacement:c,platform:a,elements:l}=e,{mainAxis:d=!0,crossAxis:u=!0,fallbackPlacements:g,fallbackStrategy:f="bestFit",fallbackAxisSideDirection:m="none",flipAlignment:h=!0,...w}=U(t,e);if((n=r.arrow)!=null&&n.alignmentOffset)return{};let p=V(i),x=W(c),y=V(c)===c,b=await(a.iLine truncated
|
||||
Reference in new issue
Block a user