init commit
This commit is contained in:
65
shared/utils/src/try-scroll.ts
Normal file
65
shared/utils/src/try-scroll.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import type { Logger } from '@amp/web-apps-logger';
|
||||
export interface ScrollableElement {
|
||||
scrollTop: number;
|
||||
scrollHeight: number;
|
||||
offsetHeight: number;
|
||||
}
|
||||
|
||||
// Global is okay here as this only runs in the browser
|
||||
let nextTry: number | null = null;
|
||||
|
||||
export function tryScroll(
|
||||
log: Logger,
|
||||
getScrollablePageElement: Function,
|
||||
scrollY: number,
|
||||
): void {
|
||||
let tries = 0;
|
||||
|
||||
if (nextTry !== null) {
|
||||
window.cancelAnimationFrame(nextTry);
|
||||
}
|
||||
|
||||
nextTry = window.requestAnimationFrame(function doNextTry() {
|
||||
// At 16ms per frame, this is 1600ms
|
||||
// See: https://github.com/DockYard/ember-router-scroll/blob/2f17728f/addon/services/router-scroll.js#L56
|
||||
if (++tries >= 100) {
|
||||
log.warn("wasn't able to restore scroll within 100 frames");
|
||||
nextTry = null;
|
||||
return;
|
||||
}
|
||||
|
||||
let element = getScrollablePageElement();
|
||||
if (!element) {
|
||||
log.warn(
|
||||
'could not restore scroll: the scrollable element is missing',
|
||||
);
|
||||
return;
|
||||
}
|
||||
const { scrollHeight, offsetHeight } = element;
|
||||
|
||||
// Only scroll once we're able to get a full screen of content when
|
||||
// scrollTop is set to scrollY
|
||||
//
|
||||
// +16 is a bit of a fudge factor to count for imperfections in
|
||||
// features like lazy loading. If the scroll position to restore is
|
||||
// the very bottom of the page, then scrollY + offsetHeight must be
|
||||
// exactly scrollHeight. But if lazy loading components (for example)
|
||||
// cause the page to grow by a few pixels, then this will never hold.
|
||||
// Thus, we fudge by a few pixels to be more forgiving in this scenario.
|
||||
const canScroll = scrollY + offsetHeight <= scrollHeight + 16;
|
||||
|
||||
if (!canScroll) {
|
||||
log.info('page is not tall enough for scroll yet', {
|
||||
scrollHeight,
|
||||
offsetHeight,
|
||||
});
|
||||
|
||||
nextTry = window.requestAnimationFrame(doNextTry);
|
||||
return;
|
||||
}
|
||||
|
||||
element.scrollTop = scrollY;
|
||||
log.info('scroll restored to', scrollY);
|
||||
nextTry = null;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user