diff --git a/src/utils/focusBlock.ts b/src/utils/focusBlock.ts index fcf23cc2..66a06f4c 100644 --- a/src/utils/focusBlock.ts +++ b/src/utils/focusBlock.ts @@ -24,6 +24,8 @@ export function focusBlock( scrollIntoViewIfNeeded( document.getElementById(elementId.block(block.value).container), false, + undefined, + -80, ); if (block.type === "math" || block.type === "code") { let el = document.getElementById( diff --git a/src/utils/scrollIntoViewIfNeeded.ts b/src/utils/scrollIntoViewIfNeeded.ts index 583d762d..c9ada15c 100644 --- a/src/utils/scrollIntoViewIfNeeded.ts +++ b/src/utils/scrollIntoViewIfNeeded.ts @@ -2,25 +2,73 @@ export function scrollIntoViewIfNeeded( el: Element | null, centerIfNeeded: boolean = true, behavior?: ScrollBehavior, + rootBottomMargin?: number, ) { + console.log("this should scroll up now!"); + if (!el) { return; } - let observer = new IntersectionObserver(function ([entry]) { - const ratio = entry.intersectionRatio; - - if (ratio < 1) { - let place = - ratio <= 0 && centerIfNeeded - ? ("center" as const) - : ("nearest" as const); - el.scrollIntoView({ - block: place, - inline: place, - behavior: behavior ? behavior : "auto", - }); - } - observer.disconnect(); - }); + + let observer = new IntersectionObserver( + function ([entry]) { + const ratio = entry.intersectionRatio; + if (ratio < 1) { + let place = + ratio <= 0 && centerIfNeeded + ? ("center" as const) + : ("nearest" as const); + el.scrollIntoView({ + block: place, + inline: place, + behavior: behavior ? behavior : "auto", + }); + + // If rootBottomMargin is defined, adjust scroll position to keep element away from bottom + if (rootBottomMargin) { + requestAnimationFrame(() => { + let rect = el.getBoundingClientRect(); + let scrollContainer = getScrollParent(el); + let scrollContainerHeight = scrollContainer.clientHeight; + let distanceFromBottom = scrollContainerHeight - rect.bottom; + + console.log("containerHeight: " + scrollContainerHeight); + console.log("el bottom: " + rect.bottom); + + scrollContainer.scrollBy({ + top: Math.abs(rootBottomMargin + distanceFromBottom), + behavior: behavior ? behavior : "auto", + }); + }); + } + } + observer.disconnect(); + }, + { + rootMargin: rootBottomMargin + ? `0px 0px ${rootBottomMargin}px 0px` + : "0px", + }, + ); observer.observe(el); } + +function getScrollParent(el: Element) { + let parent = el.parentElement; + + while (parent) { + const { overflow, overflowY } = window.getComputedStyle(parent); + + if ( + overflow === "auto" || + overflow === "scroll" || + overflowY === "auto" || + overflowY === "scroll" + ) { + return parent; + } + + parent = parent.parentElement; + } + return document.documentElement; +}