This repository has been archived by the owner on Jul 28, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathwordpress-element.js
101 lines (87 loc) · 2.41 KB
/
wordpress-element.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import {
createContext,
useContext as useReactContext,
useEffect as useReactEffect,
useState as useReactState,
} from '@wordpress/element';
import { hydrate as ReactHydrate } from 'react-dom';
export const EnvContext = createContext(null);
/**
* A React hook that returns the name of the environment.
*
* This is still a bit hacky. Ideally, Save components should support React
* hooks and all the environments (Edit, Save and View) should populate a
* normal context. Also, more environments could be added in the future.
*
* @returns {"edit" | "save" | "view"}
*/
export const useBlockEnvironment = () => {
try {
const env = useReactContext(EnvContext);
if (env === 'view') {
return 'view';
}
return 'edit';
} catch (e) {
return 'save';
}
};
const noop = () => {};
export const useState = (init) =>
useBlockEnvironment() !== 'save' ? useReactState(init) : [init, noop];
export const useEffect = (...args) =>
useBlockEnvironment() !== 'save' ? useReactEffect(...args) : noop;
export const useContext = (Context) =>
useBlockEnvironment() !== 'save'
? useReactContext(Context)
: Context._currentValue;
export const hydrate = (element, container, hydrationOptions) => {
const { technique, media } = hydrationOptions || {};
const cb = () => {
ReactHydrate(element, container);
};
switch (technique) {
case 'media':
if (media) {
const mql = matchMedia(media);
if (mql.matches) {
cb();
} else {
mql.addEventListener('change', cb, { once: true });
}
}
break;
// Hydrate the element when is visible in the viewport.
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
case 'view':
try {
const io = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) {
continue;
}
// As soon as we hydrate, disconnect this IntersectionObserver.
io.disconnect();
cb();
break; // Break loop on first match.
}
});
io.observe(container.children[0]);
} catch (e) {
cb();
}
break;
case 'idle':
// Safari does not support requestIdleCalback, we use a timeout instead.
// https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
if ('requestIdleCallback' in window) {
window.requestIdleCallback(cb);
} else {
setTimeout(cb, 200);
}
break;
// Hydrate this component immediately.
default:
cb();
}
};