fix(playlists): flip the add-to-playlist popover up when it would overflow

The popover was always positioned below its trigger, so on cards near the bottom
of the viewport it ran off-screen. Measure the panel's real height and open it
upward (clamped to the viewport) when there isn't room below; also clamp the
horizontal position.
This commit is contained in:
npeter83 2026-06-15 14:52:57 +02:00
parent 40a44cdde2
commit fb5a2f1ed2

View file

@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from "react";
import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { useQuery, useQueryClient } from "@tanstack/react-query";
@ -29,14 +29,27 @@ export default function AddToPlaylist({
enabled: open,
});
// Re-place once the panel is actually rendered (so we know its real height) and whenever
// its content — hence height — changes, so the flip-above decision uses the true size.
useLayoutEffect(() => {
if (open) place();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open, membership.data]);
function place() {
const r = triggerRef.current?.getBoundingClientRect();
if (!r) return;
const width = 240;
setCoords({
top: Math.round(r.bottom + 6),
left: Math.round(Math.min(r.left, window.innerWidth - width - 8)),
});
const margin = 8;
// Use the panel's real height once it's mounted; estimate on the first open.
const h = panelRef.current?.offsetHeight ?? 300;
let top = r.bottom + 6;
if (top + h > window.innerHeight - margin) {
// Not enough room below — open upward, clamped to the viewport.
top = Math.max(margin, r.top - h - 6);
}
const left = Math.min(Math.max(margin, r.left), window.innerWidth - width - margin);
setCoords({ top: Math.round(top), left: Math.round(left) });
}
function toggleOpen(e: React.MouseEvent) {