fix(client): preserve scroll position of preview iframe (#47870)

* fix(client): preserve scroll position of preview iframe

* use existing frameContext instead of getting element

* do not use type guard

* remove unused type, add es2022 to ts-lib

* move scroll functions into a class

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>
pull/48178/head
Sawjan Gurung 2022-10-21 23:07:15 +05:45 committed by GitHub
parent 7f1b136e40
commit 8ea0401c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 1 deletions

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { mainPreviewId } from '../utils/frame';
import { mainPreviewId, scrollManager } from '../utils/frame';
import './preview.css';
@ -29,6 +29,12 @@ function Preview({
setIframeStatus(disableIframe);
}, [disableIframe]);
useEffect(() => {
return () => {
scrollManager.setPreviewScrollPosition(0);
};
}, []);
const id = previewId ?? mainPreviewId;
return (

View File

@ -41,6 +41,35 @@ type InitFrame = (
frameConsoleLogger?: ProxyLogger
) => (frameContext: Context) => Context;
class ScrollManager {
#previewScrollPosition = 0;
getPreviewScrollPosition = () => {
return this.#previewScrollPosition;
};
setPreviewScrollPosition = (position: number) => {
this.#previewScrollPosition = position;
};
registerScrollEventListener = (iframe: HTMLIFrameElement) => {
iframe.contentDocument?.addEventListener('scroll', event => {
const currentTarget = event.currentTarget as Document | null;
if (currentTarget?.body.scrollTop) {
this.setPreviewScrollPosition(currentTarget?.body.scrollTop);
}
});
};
restorePreviewScrollPosition = (iframe: HTMLIFrameElement) => {
if (iframe.contentDocument?.body) {
iframe.contentDocument.body.scrollTop = this.#previewScrollPosition;
}
};
}
export const scrollManager = new ScrollManager();
// we use two different frames to make them all essentially pure functions
// main iframe is responsible rendering the preview and is where we proxy the
export const mainPreviewId = 'fcc-main-frame';
@ -267,6 +296,12 @@ const writeContentToFrame = (frameContext: Context) => {
createHeader(frameContext.element.id) + frameContext.build,
frameContext.document
);
scrollManager.registerScrollEventListener(frameContext.element);
if (scrollManager.getPreviewScrollPosition()) {
scrollManager.restorePreviewScrollPosition(frameContext.element);
}
return frameContext;
};