Merge pull request #138 from JipFr/v3

Move PopoutSection scrolling center to ScrollToActive component with improved logic
This commit is contained in:
mrjvs 2023-02-09 12:57:33 +01:00 committed by GitHub
commit d89bbaef97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 56 additions and 9 deletions

View File

@ -13,10 +13,17 @@ interface PopoutListEntryTypes {
errored?: boolean; errored?: boolean;
} }
export function PopoutSection(props: { interface ScrollToActiveProps {
children: React.ReactNode;
className?: string;
}
interface PopoutSectionProps {
children?: React.ReactNode; children?: React.ReactNode;
className?: string; className?: string;
}) { }
export function ScrollToActive(props: ScrollToActiveProps) {
const ref = createRef<HTMLDivElement>(); const ref = createRef<HTMLDivElement>();
const inited = useRef<boolean>(false); const inited = useRef<boolean>(false);
@ -24,27 +31,67 @@ export function PopoutSection(props: {
useEffect(() => { useEffect(() => {
if (inited.current) return; if (inited.current) return;
if (!ref.current) return; if (!ref.current) return;
const el = ref.current as HTMLDivElement; const el = ref.current as HTMLDivElement;
const active: HTMLDivElement | null = el.querySelector(".active");
if (active) { // Find nearest scroll container, or self
active?.scrollIntoView({ 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", block: "nearest",
inline: "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; inited.current = true;
}, [ref]); }, [ref]);
return ( return (
<div className={["p-5", props.className || ""].join(" ")} ref={ref}> <div className={props.className} ref={ref}>
{props.children} {props.children}
</div> </div>
); );
} }
export function PopoutSection(props: PopoutSectionProps) {
return (
<ScrollToActive className={["p-5", props.className || ""].join(" ")}>
{props.children}
</ScrollToActive>
);
}
export function PopoutListEntry(props: PopoutListEntryTypes) { export function PopoutListEntry(props: PopoutListEntryTypes) {
const bg = props.isOnDarkBackground ? "bg-ash-200" : "bg-ash-400"; const bg = props.isOnDarkBackground ? "bg-ash-200" : "bg-ash-400";
const hover = props.isOnDarkBackground const hover = props.isOnDarkBackground