diff --git a/src/video/components/popouts/PopoutUtils.tsx b/src/video/components/popouts/PopoutUtils.tsx index 867de87f..3420e77f 100644 --- a/src/video/components/popouts/PopoutUtils.tsx +++ b/src/video/components/popouts/PopoutUtils.tsx @@ -13,10 +13,17 @@ interface PopoutListEntryTypes { errored?: boolean; } -export function PopoutSection(props: { +interface ScrollToActiveProps { + children: React.ReactNode; + className?: string; +} + +interface PopoutSectionProps { children?: React.ReactNode; className?: string; -}) { +} + +export function ScrollToActive(props: ScrollToActiveProps) { const ref = createRef(); const inited = useRef(false); @@ -24,27 +31,67 @@ export function PopoutSection(props: { useEffect(() => { if (inited.current) return; if (!ref.current) return; + const el = ref.current as HTMLDivElement; - const active: HTMLDivElement | null = el.querySelector(".active"); - if (active) { - active?.scrollIntoView({ + + // Find nearest scroll container, or self + const wrapper: HTMLDivElement | null = el.classList.contains( + "overflow-y-auto" + ) + ? el + : el.closest(".overflow-y-auto"); + + const active: HTMLDivElement | null | undefined = + wrapper?.querySelector(".active"); + + if (wrapper && active) { + active.scrollIntoView({ block: "nearest", inline: "nearest", }); - el.scrollTo({ - top: el.scrollTop + el.offsetHeight / 2 - active.offsetHeight / 2, - }); + + let activeYPositionCentered = 0; + const setActiveYPositionCentered = () => { + activeYPositionCentered = + active.getBoundingClientRect().top - + wrapper.getBoundingClientRect().top + + active.offsetHeight / 2; + }; + setActiveYPositionCentered(); + + if (activeYPositionCentered >= wrapper.offsetHeight / 2) { + // Check if the active element is below the vertical center line, then scroll it into center + wrapper.scrollTo({ + top: activeYPositionCentered - wrapper.offsetHeight / 2, + }); + } + + setActiveYPositionCentered(); + if (activeYPositionCentered > wrapper.offsetHeight / 2) { + // If the element is over the vertical center line, scroll to the end + wrapper.scrollTo({ + top: wrapper.scrollHeight, + }); + } } inited.current = true; }, [ref]); return ( -
+
{props.children}
); } +export function PopoutSection(props: PopoutSectionProps) { + return ( + + {props.children} + + ); +} + export function PopoutListEntry(props: PopoutListEntryTypes) { const bg = props.isOnDarkBackground ? "bg-ash-200" : "bg-ash-400"; const hover = props.isOnDarkBackground