Skip to content

Commit 061a038

Browse files
koddssonkeithamus
andcommitted
Copy lazy-define.ts from github/github
Co-authored-by: Keith Cirkel <keithamus@users.noreply.github.com>
1 parent 6dd8ff9 commit 061a038

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

src/lazy-define.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const dynamicElements = new Map<string, Array<() => void>>()
2+
3+
const ready = new Promise<void>(resolve => {
4+
if (document.readyState === 'interactive' || document.readyState === 'complete') {
5+
resolve()
6+
} else {
7+
document.addEventListener('DOMContentLoaded', () => resolve(), {once: true})
8+
}
9+
})
10+
11+
const firstInteraction = new Promise<void>(resolve => {
12+
const handler = () => {
13+
resolve()
14+
document.removeEventListener('click', handler)
15+
document.removeEventListener('touchstart', handler)
16+
document.removeEventListener('keydown', handler)
17+
}
18+
document.addEventListener('click', handler)
19+
document.addEventListener('touchstart', handler, {passive: true})
20+
document.addEventListener('keydown', handler)
21+
})
22+
23+
const strategies = {
24+
ready,
25+
firstInteraction
26+
}
27+
28+
const timers = new WeakMap<Element, number>()
29+
function scan(node: Element = document.body) {
30+
cancelAnimationFrame(timers.get(node) || 0)
31+
timers.set(
32+
node,
33+
requestAnimationFrame(() => {
34+
for (const tagName of dynamicElements.keys()) {
35+
const child: Element | null = node.matches(tagName) ? node : node.querySelector(tagName)
36+
if (customElements.get(tagName) || child) {
37+
const strategyName = (child?.getAttribute('data-load-on') || 'ready') as keyof typeof strategies
38+
const strategy = strategyName in strategies ? strategies[strategyName] : strategies.ready
39+
// eslint-disable-next-line github/no-then
40+
for (const cb of dynamicElements.get(tagName) || []) strategy.then(cb)
41+
dynamicElements.delete(tagName)
42+
timers.delete(node)
43+
}
44+
}
45+
})
46+
)
47+
}
48+
49+
const elementLoader = new MutationObserver(mutations => {
50+
if (!dynamicElements.size) return
51+
for (const mutation of mutations) {
52+
for (const node of mutation.addedNodes) {
53+
if (node instanceof Element) scan(node)
54+
}
55+
}
56+
})
57+
elementLoader.observe(document, {subtree: true, childList: true})
58+
59+
let first = true
60+
export function whenSeen(tagName: string, callback: () => void) {
61+
if (!dynamicElements.has(tagName)) dynamicElements.set(tagName, [])
62+
dynamicElements.get(tagName)!.push(callback)
63+
64+
if (first) scan(document.body)
65+
first = false
66+
}

0 commit comments

Comments
 (0)