mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-12-15 20:55:29 +08:00
Expand lazy creation of editor and JS Views to the proximity of the viewport (#2445)
This commit is contained in:
parent
22cd0c233a
commit
e038ff790b
3 changed files with 47 additions and 16 deletions
|
|
@ -65,7 +65,10 @@ const CellEditor = {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.visibility = waitUntilInViewport(this.el);
|
this.visibility = waitUntilInViewport(this.el, {
|
||||||
|
root: document.querySelector("[data-el-notebook]"),
|
||||||
|
proximity: 2000,
|
||||||
|
});
|
||||||
|
|
||||||
// We mount the editor lazily once it enters the viewport
|
// We mount the editor lazily once it enters the viewport
|
||||||
this.visibility.promise.then(() => {
|
this.visibility.promise.then(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { parseHookProps } from "../lib/attribute";
|
import { parseHookProps } from "../lib/attribute";
|
||||||
import {
|
import {
|
||||||
isElementHidden,
|
isElementHidden,
|
||||||
isElementVisibleInViewport,
|
|
||||||
randomId,
|
randomId,
|
||||||
randomToken,
|
randomToken,
|
||||||
waitUntilInViewport,
|
waitUntilInViewport,
|
||||||
|
|
@ -258,7 +257,10 @@ const JSView = {
|
||||||
// We detect when the placeholder enters viewport and becomes visible,
|
// We detect when the placeholder enters viewport and becomes visible,
|
||||||
// based on that we can load the iframe contents lazily
|
// based on that we can load the iframe contents lazily
|
||||||
|
|
||||||
const visibility = waitUntilInViewport(this.iframePlaceholder);
|
const visibility = waitUntilInViewport(this.iframePlaceholder, {
|
||||||
|
root: notebookEl,
|
||||||
|
proximity: 2000,
|
||||||
|
});
|
||||||
|
|
||||||
// Reflect focus based on whether there is a focused parent, this
|
// Reflect focus based on whether there is a focused parent, this
|
||||||
// is later synced on "element_focused" events
|
// is later synced on "element_focused" events
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ export function isEditableElement(element) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isElementInViewport(element) {
|
export function isElementInViewport(element, proximity = 0) {
|
||||||
const box = element.getBoundingClientRect();
|
const box = element.getBoundingClientRect();
|
||||||
return box.bottom >= 0 && box.top <= window.innerHeight;
|
return box.bottom >= -proximity && box.top <= window.innerHeight + proximity;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isElementHidden(element) {
|
export function isElementHidden(element) {
|
||||||
|
|
@ -39,20 +39,46 @@ export function waitUntilVisible(element) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function waitUntilInViewport(element) {
|
/**
|
||||||
|
* Returns a promise that resolves when the element enters the viewport.
|
||||||
|
*
|
||||||
|
* ## Options
|
||||||
|
*
|
||||||
|
* * `root` - a scrollable ancestor that should be used for observing
|
||||||
|
* the intersection, instead of the viewport
|
||||||
|
*
|
||||||
|
* * `proximity` - the number of pixels around `root` used to expand
|
||||||
|
* the intersection box, which effectively resolves the promise when
|
||||||
|
* `element` is in certain proximity of the viewport. Note that if
|
||||||
|
* the element is inside a scrollable ancestor, the ancestor must
|
||||||
|
* be set as `root`.
|
||||||
|
*
|
||||||
|
* > NOTE: rootMargin only applies to the intersection root itself.
|
||||||
|
* > If a target Element is clipped by an ancestor other than the
|
||||||
|
* > intersection root, that clipping is unaffected by rootMargin.
|
||||||
|
* > ~ https://w3c.github.io/IntersectionObserver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function waitUntilInViewport(
|
||||||
|
element,
|
||||||
|
{ root = null, proximity = 0 } = {}
|
||||||
|
) {
|
||||||
let observer = null;
|
let observer = null;
|
||||||
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
if (isElementVisibleInViewport(element)) {
|
if (isElementVisibleInViewport(element, proximity)) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
observer = new IntersectionObserver((entries) => {
|
observer = new IntersectionObserver(
|
||||||
if (isElementVisibleInViewport(element)) {
|
(entries) => {
|
||||||
observer.disconnect();
|
if (entries[0].isIntersecting) {
|
||||||
observer = null;
|
observer.disconnect();
|
||||||
resolve();
|
observer = null;
|
||||||
}
|
resolve();
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
{ root, rootMargin: `${proximity}px` }
|
||||||
|
);
|
||||||
observer.observe(element);
|
observer.observe(element);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -64,8 +90,8 @@ export function waitUntilInViewport(element) {
|
||||||
return { promise, cancel };
|
return { promise, cancel };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isElementVisibleInViewport(element) {
|
export function isElementVisibleInViewport(element, proximity = 0) {
|
||||||
return !isElementHidden(element) && isElementInViewport(element);
|
return !isElementHidden(element) && isElementInViewport(element, proximity);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clamp(n, x, y) {
|
export function clamp(n, x, y) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue