@tamagui/use-element-layout 1.134.4 → 1.135.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +50 -31
- package/dist/cjs/index.js +72 -66
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/index.native.js +93 -81
- package/dist/cjs/index.native.js.map +3 -3
- package/dist/esm/index.js +73 -65
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/index.mjs +49 -31
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +88 -69
- package/dist/esm/index.native.js.map +1 -1
- package/package.json +4 -4
- package/src/{index.ts → index.tsx} +125 -109
- package/types/index.d.ts +8 -1
- package/types/index.d.ts.map +3 -3
package/dist/esm/index.native.js
CHANGED
|
@@ -1,17 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import { isClient, useIsomorphicLayoutEffect } from "@tamagui/constants";
|
|
2
3
|
import { isEqualShallow } from "@tamagui/is-equal-shallow";
|
|
4
|
+
import { createContext, useContext, useId } from "react";
|
|
3
5
|
var LayoutHandlers = /* @__PURE__ */new WeakMap(),
|
|
6
|
+
LayoutDisableKey = /* @__PURE__ */new WeakMap(),
|
|
4
7
|
Nodes = /* @__PURE__ */new Set(),
|
|
5
8
|
IntersectionState = /* @__PURE__ */new WeakMap(),
|
|
9
|
+
DisableLayoutContextValues = {},
|
|
10
|
+
DisableLayoutContextKey = /* @__PURE__ */createContext(""),
|
|
11
|
+
ENABLE = isClient && typeof IntersectionObserver < "u",
|
|
12
|
+
LayoutMeasurementController = function (param) {
|
|
13
|
+
var {
|
|
14
|
+
disable,
|
|
15
|
+
children
|
|
16
|
+
} = param,
|
|
17
|
+
id = useId();
|
|
18
|
+
return useIsomorphicLayoutEffect(function () {
|
|
19
|
+
DisableLayoutContextValues[id] = disable;
|
|
20
|
+
}, [disable, id]), /* @__PURE__ */_jsx(DisableLayoutContextKey.Provider, {
|
|
21
|
+
value: id,
|
|
22
|
+
children
|
|
23
|
+
});
|
|
24
|
+
},
|
|
6
25
|
globalIntersectionObserver = null,
|
|
7
26
|
strategy = "async";
|
|
8
27
|
function setOnLayoutStrategy(state) {
|
|
9
28
|
strategy = state;
|
|
10
29
|
}
|
|
11
30
|
var NodeRectCache = /* @__PURE__ */new WeakMap(),
|
|
12
|
-
ParentRectCache = /* @__PURE__ */new WeakMap(),
|
|
13
31
|
LastChangeTime = /* @__PURE__ */new WeakMap(),
|
|
14
|
-
rAF = typeof window < "u" ? window.requestAnimationFrame : void 0,
|
|
15
32
|
avoidUpdates = !0,
|
|
16
33
|
queuedUpdates = /* @__PURE__ */new Map();
|
|
17
34
|
function enable() {
|
|
@@ -20,7 +37,7 @@ function enable() {
|
|
|
20
37
|
}), queuedUpdates.clear()));
|
|
21
38
|
}
|
|
22
39
|
function startGlobalObservers() {
|
|
23
|
-
!
|
|
40
|
+
!ENABLE || globalIntersectionObserver || (globalIntersectionObserver = new IntersectionObserver(function (entries) {
|
|
24
41
|
entries.forEach(function (entry) {
|
|
25
42
|
var node = entry.target;
|
|
26
43
|
IntersectionState.get(node) !== entry.isIntersecting && IntersectionState.set(node, entry.isIntersecting);
|
|
@@ -29,30 +46,29 @@ function startGlobalObservers() {
|
|
|
29
46
|
threshold: 0
|
|
30
47
|
}));
|
|
31
48
|
}
|
|
32
|
-
if (
|
|
33
|
-
var
|
|
34
|
-
BoundingRects = /* @__PURE__ */new WeakMap();
|
|
49
|
+
if (ENABLE) {
|
|
50
|
+
var BoundingRects = /* @__PURE__ */new WeakMap();
|
|
35
51
|
async function updateLayoutIfChanged(node) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
var onLayout = LayoutHandlers.get(node);
|
|
53
|
+
if (typeof onLayout == "function") {
|
|
54
|
+
var parentNode = node.parentElement;
|
|
55
|
+
if (parentNode) {
|
|
56
|
+
var nodeRect, parentRect;
|
|
57
|
+
if (strategy === "async") {
|
|
58
|
+
var [nr, pr] = await Promise.all([BoundingRects.get(node), BoundingRects.get(parentNode)]);
|
|
59
|
+
if (!nr || !pr) return;
|
|
60
|
+
nodeRect = nr, parentRect = pr;
|
|
61
|
+
} else nodeRect = node.getBoundingClientRect(), parentRect = parentNode.getBoundingClientRect();
|
|
62
|
+
if (!(!nodeRect || !parentRect)) {
|
|
47
63
|
var cachedRect = NodeRectCache.get(node),
|
|
48
64
|
cachedParentRect = NodeRectCache.get(parentNode);
|
|
49
|
-
if (!cachedRect ||
|
|
65
|
+
if (!cachedRect || !cachedParentRect ||
|
|
50
66
|
// has changed one rect
|
|
51
67
|
// @ts-expect-error DOMRectReadOnly can go into object
|
|
52
|
-
!isEqualShallow(cachedRect, nodeRect)
|
|
68
|
+
!isEqualShallow(cachedRect, nodeRect) ||
|
|
53
69
|
// @ts-expect-error DOMRectReadOnly can go into object
|
|
54
|
-
!
|
|
55
|
-
NodeRectCache.set(node, nodeRect),
|
|
70
|
+
!isEqualShallow(cachedParentRect, parentRect)) {
|
|
71
|
+
NodeRectCache.set(node, nodeRect), NodeRectCache.set(parentNode, parentRect);
|
|
56
72
|
var event = getElementLayoutEvent(nodeRect, parentRect);
|
|
57
73
|
avoidUpdates ? queuedUpdates.set(node, function () {
|
|
58
74
|
return onLayout(event);
|
|
@@ -62,64 +78,66 @@ if (isClient) if (rAF) {
|
|
|
62
78
|
}
|
|
63
79
|
}
|
|
64
80
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP,
|
|
68
|
-
RUN_EVERY_X_FRAMES = userSkipVal ? +userSkipVal : 10;
|
|
81
|
+
var userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP,
|
|
82
|
+
RUN_EVERY_X_FRAMES = userSkipVal ? +userSkipVal : 14;
|
|
69
83
|
async function layoutOnAnimationFrame() {
|
|
70
84
|
if (strategy !== "off") {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
var _iteratorNormalCompletion2 = !0,
|
|
79
|
-
_didIteratorError2 = !1,
|
|
80
|
-
_iteratorError2 = void 0;
|
|
81
|
-
try {
|
|
82
|
-
for (var _iterator2 = entries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = !0) {
|
|
83
|
-
var entry = _step2.value;
|
|
84
|
-
BoundingRects.set(entry.target, entry.boundingClientRect);
|
|
85
|
-
}
|
|
86
|
-
} catch (err) {
|
|
87
|
-
_didIteratorError2 = !0, _iteratorError2 = err;
|
|
88
|
-
} finally {
|
|
85
|
+
var visibleNodes = [],
|
|
86
|
+
didRun = await new Promise(function (res) {
|
|
87
|
+
var io = new IntersectionObserver(function (entries) {
|
|
88
|
+
io.disconnect();
|
|
89
|
+
var _iteratorNormalCompletion2 = !0,
|
|
90
|
+
_didIteratorError2 = !1,
|
|
91
|
+
_iteratorError2 = void 0;
|
|
89
92
|
try {
|
|
90
|
-
|
|
93
|
+
for (var _iterator2 = entries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = !0) {
|
|
94
|
+
var entry = _step2.value;
|
|
95
|
+
BoundingRects.set(entry.target, entry.boundingClientRect);
|
|
96
|
+
}
|
|
97
|
+
} catch (err) {
|
|
98
|
+
_didIteratorError2 = !0, _iteratorError2 = err;
|
|
91
99
|
} finally {
|
|
92
|
-
|
|
100
|
+
try {
|
|
101
|
+
!_iteratorNormalCompletion2 && _iterator2.return != null && _iterator2.return();
|
|
102
|
+
} finally {
|
|
103
|
+
if (_didIteratorError2) throw _iteratorError2;
|
|
104
|
+
}
|
|
93
105
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
for (var _iterator = Nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = !0) {
|
|
104
|
-
var node = _step.value;
|
|
105
|
-
node.parentElement instanceof HTMLElement && (io.observe(node), io.observe(node.parentElement));
|
|
106
|
-
}
|
|
107
|
-
} catch (err) {
|
|
108
|
-
_didIteratorError = !0, _iteratorError = err;
|
|
109
|
-
} finally {
|
|
106
|
+
res(!0);
|
|
107
|
+
}, {
|
|
108
|
+
threshold: 0
|
|
109
|
+
}),
|
|
110
|
+
didObserve = !1,
|
|
111
|
+
_iteratorNormalCompletion = !0,
|
|
112
|
+
_didIteratorError = !1,
|
|
113
|
+
_iteratorError = void 0;
|
|
110
114
|
try {
|
|
111
|
-
|
|
115
|
+
for (var _iterator = Nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = !0) {
|
|
116
|
+
var node = _step.value;
|
|
117
|
+
if (node.parentElement instanceof HTMLElement) {
|
|
118
|
+
var disableKey = LayoutDisableKey.get(node);
|
|
119
|
+
disableKey && DisableLayoutContextValues[disableKey] === !0 || IntersectionState.get(node) !== !1 && (didObserve = !0, io.observe(node), io.observe(node.parentElement), visibleNodes.push(node));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (err) {
|
|
123
|
+
_didIteratorError = !0, _iteratorError = err;
|
|
112
124
|
} finally {
|
|
113
|
-
|
|
125
|
+
try {
|
|
126
|
+
!_iteratorNormalCompletion && _iterator.return != null && _iterator.return();
|
|
127
|
+
} finally {
|
|
128
|
+
if (_didIteratorError) throw _iteratorError;
|
|
129
|
+
}
|
|
114
130
|
}
|
|
115
|
-
|
|
116
|
-
|
|
131
|
+
didObserve || res(!1);
|
|
132
|
+
});
|
|
133
|
+
didRun && visibleNodes.forEach(function (node) {
|
|
117
134
|
updateLayoutIfChanged(node);
|
|
118
135
|
});
|
|
119
136
|
}
|
|
120
|
-
|
|
137
|
+
setTimeout(layoutOnAnimationFrame, 16.6667 * RUN_EVERY_X_FRAMES);
|
|
121
138
|
}
|
|
122
|
-
|
|
139
|
+
layoutOnAnimationFrame();
|
|
140
|
+
}
|
|
123
141
|
var getElementLayoutEvent = function (nodeRect, parentRect) {
|
|
124
142
|
return {
|
|
125
143
|
nativeEvent: {
|
|
@@ -149,8 +167,9 @@ var getElementLayoutEvent = function (nodeRect, parentRect) {
|
|
|
149
167
|
};
|
|
150
168
|
function useElementLayout(ref, onLayout) {
|
|
151
169
|
var _ref_current,
|
|
170
|
+
disableKey = useContext(DisableLayoutContextKey),
|
|
152
171
|
node = ensureWebElement((_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.host);
|
|
153
|
-
node && onLayout && LayoutHandlers.set(node, onLayout), useIsomorphicLayoutEffect(function () {
|
|
172
|
+
node && onLayout && (LayoutHandlers.set(node, onLayout), LayoutDisableKey.set(node, disableKey)), useIsomorphicLayoutEffect(function () {
|
|
154
173
|
var _ref_current2;
|
|
155
174
|
if (onLayout) {
|
|
156
175
|
var node2 = (_ref_current2 = ref.current) === null || _ref_current2 === void 0 ? void 0 : _ref_current2.host;
|
|
@@ -213,5 +232,5 @@ function createMeasureLayout(node) {
|
|
|
213
232
|
return measureLayout(node, relativeTo, callback);
|
|
214
233
|
};
|
|
215
234
|
}
|
|
216
|
-
export { createMeasure, createMeasureInWindow, createMeasureLayout, enable, getBoundingClientRectAsync, getElementLayoutEvent, measure, measureInWindow, measureLayout, measureNode, setOnLayoutStrategy, useElementLayout };
|
|
235
|
+
export { LayoutMeasurementController, createMeasure, createMeasureInWindow, createMeasureLayout, enable, getBoundingClientRectAsync, getElementLayoutEvent, measure, measureInWindow, measureLayout, measureNode, setOnLayoutStrategy, useElementLayout };
|
|
217
236
|
//# sourceMappingURL=index.native.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["isClient","useIsomorphicLayoutEffect","isEqualShallow","LayoutHandlers","WeakMap","Nodes","Set","IntersectionState","
|
|
1
|
+
{"version":3,"names":["jsx","_jsx","isClient","useIsomorphicLayoutEffect","isEqualShallow","createContext","useContext","useId","LayoutHandlers","WeakMap","LayoutDisableKey","Nodes","Set","IntersectionState","DisableLayoutContextValues","DisableLayoutContextKey","ENABLE","IntersectionObserver","LayoutMeasurementController","param","disable","children","id","Provider","value","globalIntersectionObserver","strategy","setOnLayoutStrategy","state","NodeRectCache","LastChangeTime","avoidUpdates","queuedUpdates","Map","enable","forEach","cb","clear","startGlobalObservers","entries","entry","node","target","get","isIntersecting","set","threshold","BoundingRects","updateLayoutIfChanged","onLayout","parentNode","parentElement","nodeRect","parentRect","nr","pr","Promise","all","getBoundingClientRect","cachedRect","cachedParentRect","event","getElementLayoutEvent","userSkipVal","process","env","TAMAGUI_LAYOUT_FRAME_SKIP","RUN_EVERY_X_FRAMES","layoutOnAnimationFrame","visibleNodes","didRun","res","io","disconnect","_iteratorNormalCompletion2","_didIteratorError2","_iteratorError2","_iterator2","Symbol","iterator","_step2","next","done","boundingClientRect","err","return","didObserve","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","_step","HTMLElement","disableKey","observe","push","setTimeout","nativeEvent","layout","getRelativeDimensions","timeStamp","Date","now","a","b","height","left","top","width","x","y","pageX","pageY","useElementLayout","ref","_ref_current","ensureWebElement","current","host","_ref_current2","node2","add","delete","unobserve","getBoundingClientRectAsync","nodeType"],"sources":["../../src/index.tsx"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/use-element-layout",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.135.0",
|
|
4
4
|
"types": "./types/index.d.ts",
|
|
5
5
|
"main": "dist/cjs",
|
|
6
6
|
"module": "dist/esm",
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@tamagui/constants": "1.
|
|
35
|
-
"@tamagui/is-equal-shallow": "1.
|
|
34
|
+
"@tamagui/constants": "1.135.0",
|
|
35
|
+
"@tamagui/is-equal-shallow": "1.135.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@tamagui/build": "1.
|
|
38
|
+
"@tamagui/build": "1.135.0",
|
|
39
39
|
"react": "*"
|
|
40
40
|
},
|
|
41
41
|
"publishConfig": {
|
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
import { isClient, useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
2
2
|
import { isEqualShallow } from '@tamagui/is-equal-shallow'
|
|
3
|
-
import {
|
|
3
|
+
import { createContext, useContext, useId, type ReactNode, type RefObject } from 'react'
|
|
4
4
|
|
|
5
5
|
const LayoutHandlers = new WeakMap<HTMLElement, Function>()
|
|
6
|
+
const LayoutDisableKey = new WeakMap<HTMLElement, string>()
|
|
6
7
|
const Nodes = new Set<HTMLElement>()
|
|
7
8
|
const IntersectionState = new WeakMap<HTMLElement, boolean>()
|
|
8
9
|
|
|
10
|
+
// separating to avoid all re-rendering
|
|
11
|
+
const DisableLayoutContextValues: Record<string, boolean> = {}
|
|
12
|
+
const DisableLayoutContextKey = createContext<string>('')
|
|
13
|
+
|
|
14
|
+
const ENABLE = isClient && typeof IntersectionObserver !== 'undefined'
|
|
15
|
+
|
|
16
|
+
// internal testing - advanced helper to turn off layout measurement for extra performance
|
|
17
|
+
// TODO document!
|
|
18
|
+
// TODO could add frame skip control here
|
|
19
|
+
export const LayoutMeasurementController = ({
|
|
20
|
+
disable,
|
|
21
|
+
children,
|
|
22
|
+
}: {
|
|
23
|
+
disable: boolean
|
|
24
|
+
children: ReactNode
|
|
25
|
+
}): ReactNode => {
|
|
26
|
+
const id = useId()
|
|
27
|
+
|
|
28
|
+
useIsomorphicLayoutEffect(() => {
|
|
29
|
+
DisableLayoutContextValues[id] = disable
|
|
30
|
+
}, [disable, id])
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<DisableLayoutContextKey.Provider value={id}>
|
|
34
|
+
{children}
|
|
35
|
+
</DisableLayoutContextKey.Provider>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
9
39
|
// Single persistent IntersectionObserver for all nodes
|
|
10
40
|
let globalIntersectionObserver: IntersectionObserver | null = null
|
|
11
41
|
|
|
@@ -39,11 +69,8 @@ export type LayoutEvent = {
|
|
|
39
69
|
}
|
|
40
70
|
|
|
41
71
|
const NodeRectCache = new WeakMap<HTMLElement, DOMRect>()
|
|
42
|
-
const ParentRectCache = new WeakMap<HTMLElement, DOMRect>()
|
|
43
72
|
const LastChangeTime = new WeakMap<HTMLElement, number>()
|
|
44
73
|
|
|
45
|
-
const rAF = typeof window !== 'undefined' ? window.requestAnimationFrame : undefined
|
|
46
|
-
|
|
47
74
|
// prevent thrashing during first hydration (somewhat, streaming gets trickier)
|
|
48
75
|
let avoidUpdates = true
|
|
49
76
|
const queuedUpdates = new Map<HTMLElement, Function>()
|
|
@@ -59,7 +86,7 @@ export function enable(): void {
|
|
|
59
86
|
}
|
|
60
87
|
|
|
61
88
|
function startGlobalObservers() {
|
|
62
|
-
if (!
|
|
89
|
+
if (!ENABLE || globalIntersectionObserver) return
|
|
63
90
|
|
|
64
91
|
globalIntersectionObserver = new IntersectionObserver(
|
|
65
92
|
(entries) => {
|
|
@@ -76,134 +103,120 @@ function startGlobalObservers() {
|
|
|
76
103
|
)
|
|
77
104
|
}
|
|
78
105
|
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
const supportsCheckVisibility = 'checkVisibility' in document.body
|
|
106
|
+
if (ENABLE) {
|
|
107
|
+
const BoundingRects = new WeakMap<any, DOMRectReadOnly | undefined>()
|
|
82
108
|
|
|
83
|
-
|
|
109
|
+
async function updateLayoutIfChanged(node: HTMLElement) {
|
|
110
|
+
const onLayout = LayoutHandlers.get(node)
|
|
111
|
+
if (typeof onLayout !== 'function') return
|
|
84
112
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// avoid due to not intersecting
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
// triggers style recalculation in safari which is slower than not
|
|
91
|
-
if (process.env.TAMAGUI_ONLAYOUT_VISIBILITY_CHECK === '1') {
|
|
92
|
-
if (supportsCheckVisibility && !(node as any).checkVisibility()) {
|
|
93
|
-
// avoid due to not visible
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
}
|
|
113
|
+
const parentNode = node.parentElement
|
|
114
|
+
if (!parentNode) return
|
|
97
115
|
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
let nodeRect: DOMRectReadOnly
|
|
117
|
+
let parentRect: DOMRectReadOnly
|
|
100
118
|
|
|
101
|
-
|
|
102
|
-
|
|
119
|
+
if (strategy === 'async') {
|
|
120
|
+
const [nr, pr] = await Promise.all([
|
|
121
|
+
BoundingRects.get(node),
|
|
122
|
+
BoundingRects.get(parentNode),
|
|
123
|
+
])
|
|
103
124
|
|
|
104
|
-
|
|
105
|
-
|
|
125
|
+
if (!nr || !pr) {
|
|
126
|
+
return
|
|
127
|
+
}
|
|
106
128
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
129
|
+
nodeRect = nr
|
|
130
|
+
parentRect = pr
|
|
131
|
+
} else {
|
|
132
|
+
nodeRect = node.getBoundingClientRect()
|
|
133
|
+
parentRect = parentNode.getBoundingClientRect()
|
|
134
|
+
}
|
|
112
135
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
136
|
+
if (!nodeRect || !parentRect) {
|
|
137
|
+
return
|
|
138
|
+
}
|
|
116
139
|
|
|
117
|
-
|
|
118
|
-
|
|
140
|
+
const cachedRect = NodeRectCache.get(node)
|
|
141
|
+
const cachedParentRect = NodeRectCache.get(parentNode)
|
|
142
|
+
|
|
143
|
+
if (
|
|
144
|
+
!cachedRect ||
|
|
145
|
+
!cachedParentRect ||
|
|
146
|
+
// has changed one rect
|
|
147
|
+
// @ts-expect-error DOMRectReadOnly can go into object
|
|
148
|
+
!isEqualShallow(cachedRect, nodeRect) ||
|
|
149
|
+
// @ts-expect-error DOMRectReadOnly can go into object
|
|
150
|
+
!isEqualShallow(cachedParentRect, parentRect)
|
|
151
|
+
) {
|
|
152
|
+
NodeRectCache.set(node, nodeRect)
|
|
153
|
+
NodeRectCache.set(parentNode, parentRect)
|
|
154
|
+
|
|
155
|
+
const event = getElementLayoutEvent(nodeRect, parentRect)
|
|
156
|
+
|
|
157
|
+
if (avoidUpdates) {
|
|
158
|
+
queuedUpdates.set(node, () => onLayout(event))
|
|
119
159
|
} else {
|
|
120
|
-
|
|
121
|
-
parentRect = parentNode.getBoundingClientRect()
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const cachedRect = NodeRectCache.get(node)
|
|
125
|
-
const cachedParentRect = NodeRectCache.get(parentNode)
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
!cachedRect ||
|
|
129
|
-
// has changed one rect
|
|
130
|
-
// @ts-expect-error DOMRectReadOnly can go into object
|
|
131
|
-
(!isEqualShallow(cachedRect, nodeRect) &&
|
|
132
|
-
// @ts-expect-error DOMRectReadOnly can go into object
|
|
133
|
-
(!cachedParentRect || !isEqualShallow(cachedParentRect, parentRect)))
|
|
134
|
-
) {
|
|
135
|
-
NodeRectCache.set(node, nodeRect)
|
|
136
|
-
ParentRectCache.set(parentNode, parentRect)
|
|
137
|
-
|
|
138
|
-
const event = getElementLayoutEvent(nodeRect, parentRect)
|
|
139
|
-
|
|
140
|
-
if (avoidUpdates) {
|
|
141
|
-
queuedUpdates.set(node, () => onLayout(event))
|
|
142
|
-
} else {
|
|
143
|
-
onLayout(event)
|
|
144
|
-
}
|
|
160
|
+
onLayout(event)
|
|
145
161
|
}
|
|
146
162
|
}
|
|
163
|
+
}
|
|
147
164
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
rAF!(layoutOnAnimationFrame)
|
|
165
|
+
// note that getBoundingClientRect() does not thrash layout if its after an animation frame
|
|
166
|
+
// ok new note: *if* it needed recalc then yea, but browsers often skip that, so it does
|
|
167
|
+
// which is why we use async strategy in general
|
|
152
168
|
|
|
153
|
-
|
|
154
|
-
|
|
169
|
+
const userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP
|
|
170
|
+
const RUN_EVERY_X_FRAMES = userSkipVal ? +userSkipVal : 14
|
|
155
171
|
|
|
156
|
-
|
|
157
|
-
|
|
172
|
+
async function layoutOnAnimationFrame() {
|
|
173
|
+
if (strategy !== 'off') {
|
|
174
|
+
const visibleNodes: HTMLElement[] = []
|
|
158
175
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
176
|
+
// do a 1 rather than N IntersectionObservers for performance
|
|
177
|
+
const didRun = await new Promise<boolean>((res) => {
|
|
178
|
+
const io = new IntersectionObserver(
|
|
179
|
+
(entries) => {
|
|
180
|
+
io.disconnect()
|
|
181
|
+
for (const entry of entries) {
|
|
182
|
+
BoundingRects.set(entry.target, entry.boundingClientRect)
|
|
183
|
+
}
|
|
184
|
+
res(true)
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
threshold: 0,
|
|
188
|
+
}
|
|
189
|
+
)
|
|
166
190
|
|
|
167
|
-
|
|
168
|
-
|
|
191
|
+
let didObserve = false
|
|
192
|
+
|
|
193
|
+
for (const node of Nodes) {
|
|
194
|
+
if (!(node.parentElement instanceof HTMLElement)) continue
|
|
195
|
+
const disableKey = LayoutDisableKey.get(node)
|
|
196
|
+
if (disableKey && DisableLayoutContextValues[disableKey] === true) continue
|
|
197
|
+
if (IntersectionState.get(node) === false) continue
|
|
198
|
+
didObserve = true
|
|
199
|
+
io.observe(node)
|
|
200
|
+
io.observe(node.parentElement)
|
|
201
|
+
visibleNodes.push(node)
|
|
169
202
|
}
|
|
170
203
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
io.disconnect()
|
|
176
|
-
for (const entry of entries) {
|
|
177
|
-
BoundingRects.set(entry.target, entry.boundingClientRect)
|
|
178
|
-
}
|
|
179
|
-
res()
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
threshold: 0,
|
|
183
|
-
}
|
|
184
|
-
)
|
|
185
|
-
for (const node of Nodes) {
|
|
186
|
-
if (node.parentElement instanceof HTMLElement) {
|
|
187
|
-
io.observe(node)
|
|
188
|
-
io.observe(node.parentElement)
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
})
|
|
204
|
+
if (!didObserve) {
|
|
205
|
+
res(false)
|
|
206
|
+
}
|
|
207
|
+
})
|
|
192
208
|
|
|
193
|
-
|
|
209
|
+
if (didRun) {
|
|
210
|
+
visibleNodes.forEach((node) => {
|
|
194
211
|
updateLayoutIfChanged(node)
|
|
195
212
|
})
|
|
196
213
|
}
|
|
197
|
-
|
|
198
|
-
rAF!(layoutOnAnimationFrame)
|
|
199
|
-
}
|
|
200
|
-
} else {
|
|
201
|
-
if (process.env.NODE_ENV === 'development') {
|
|
202
|
-
console.warn(
|
|
203
|
-
`No requestAnimationFrame - please polyfill for onLayout to work correctly`
|
|
204
|
-
)
|
|
205
214
|
}
|
|
215
|
+
|
|
216
|
+
setTimeout(layoutOnAnimationFrame, 16.6667 * RUN_EVERY_X_FRAMES)
|
|
206
217
|
}
|
|
218
|
+
|
|
219
|
+
layoutOnAnimationFrame()
|
|
207
220
|
}
|
|
208
221
|
|
|
209
222
|
export const getElementLayoutEvent = (
|
|
@@ -230,10 +243,13 @@ export function useElementLayout(
|
|
|
230
243
|
ref: RefObject<TamaguiComponentStatePartial>,
|
|
231
244
|
onLayout?: ((e: LayoutEvent) => void) | null
|
|
232
245
|
): void {
|
|
246
|
+
const disableKey = useContext(DisableLayoutContextKey)
|
|
247
|
+
|
|
233
248
|
// ensure always up to date so we can avoid re-running effect
|
|
234
249
|
const node = ensureWebElement(ref.current?.host)
|
|
235
250
|
if (node && onLayout) {
|
|
236
251
|
LayoutHandlers.set(node, onLayout)
|
|
252
|
+
LayoutDisableKey.set(node, disableKey)
|
|
237
253
|
}
|
|
238
254
|
|
|
239
255
|
useIsomorphicLayoutEffect(() => {
|
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import { type RefObject } from "react";
|
|
1
|
+
import { type ReactNode, type RefObject } from "react";
|
|
2
|
+
// internal testing - advanced helper to turn off layout measurement for extra performance
|
|
3
|
+
// TODO document!
|
|
4
|
+
// TODO could add frame skip control here
|
|
5
|
+
export declare const LayoutMeasurementController: ({ disable, children }: {
|
|
6
|
+
disable: boolean;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}) => ReactNode;
|
|
2
9
|
type TamaguiComponentStatePartial = {
|
|
3
10
|
host?: any;
|
|
4
11
|
};
|