app: Drop hacks that preserved docs scroll.

The iframe automatically scrolled to 0 when CSS `display: none` is set, so we had several workarounds. Hide it instead.
This commit is contained in:
Laurens Valk
2026-03-30 14:24:14 +02:00
parent 98d2e82240
commit a09383de68
2 changed files with 11 additions and 66 deletions
+1 -63
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2023 The Pybricks Authors
// Copyright (c) 2020-2026 The Pybricks Authors
import 'react-splitter-layout/lib/index.css';
import './app.scss';
@@ -52,17 +52,7 @@ const Docs: React.FunctionComponent = () => {
return (
<iframe
// REVISIT: some of this could be moved to the docs repo
// so that it runs earlier to prevent flashing in the UI.
// The load event doesn't run until after the page is fully
// loaded and there doesn't seem to be a reasonable way to
// hook into the iframe to know when it has a new document.
onLoad={(e) => {
// HACK: this mess restores the scroll position when
// the documentation iframe visibility is toggled.
// The iframe will be automatically scrolled to 0 when
// CSS `display: none` is set.
const target = e.target as HTMLIFrameElement;
const contentWindow = target.contentWindow;
if (!contentWindow) {
@@ -70,58 +60,6 @@ const Docs: React.FunctionComponent = () => {
return;
}
// the last "good" scrollY value of the iframe
let iframeScroll = 0;
// This bit monitors the visibility.
// https://stackoverflow.com/a/44670818/1976323
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
// Restore the scroll position when the iframe is
// shown. Toggling the visibility prevents flashing
// the contents from the top of the page before the
// scroll is done.
if (entry.intersectionRatio > 0) {
contentWindow.scrollTo(0, iframeScroll);
contentWindow.document.documentElement.style.visibility =
'visible';
} else {
contentWindow.document.documentElement.style.visibility =
'hidden';
}
});
},
{
root: target.parentElement,
},
);
observer.observe(target);
// Have to remove he observer, otherwise we end up with
// conflicting values when a new page is loaded in the iframe.
contentWindow.addEventListener('unload', () => {
observer.unobserve(target);
});
// And this keeps track of the scroll position.
contentWindow.addEventListener('scroll', () => {
if (contentWindow.scrollY !== 0) {
// Record the current scroll position. If it is 0, it
// could be that the iframe has been hidden or the user
// scrolled there. So we have to ignore 0. But we don't
// want to be one pixel off if the user really did
// scroll there, so we assume that if the last scroll
// is 1, then the user probably went all the way to 0.
if (contentWindow.scrollY === 1) {
iframeScroll = 0;
} else {
iframeScroll = contentWindow.scrollY;
}
}
});
// Override browser default key bindings in iframe.
contentWindow.document.addEventListener('keydown', (e) => {
// use Ctrl-D/Cmd-D to toggle docs
+10 -3
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2022 The Pybricks Authors
// Copyright (c) 2020-2026 The Pybricks Authors
// Custom styling for the App control.
@@ -184,7 +184,14 @@ $dark-splitter-color-hover: color.adjust(
}
// hide the docs and resize separator
// Use visibility rather than display:none so the iframe keeps its layout and
// scroll position when the docs panel is toggled.
// Collapse the secondary pane and splitter to zero width so they don't
// consume space, while keeping the iframe in the DOM.
div.pb-hide-docs > :not(.layout-pane-primary) {
display: none;
visibility: hidden;
pointer-events: none;
flex-basis: 0 !important;
width: 0 !important;
min-width: 0 !important;
}