@tamagui/use-element-layout 2.0.0-rc.3 → 2.0.0-rc.31
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 +123 -53
- package/dist/cjs/index.native.js +181 -86
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/esm/index.js +198 -136
- package/dist/esm/index.js.map +1 -6
- package/dist/esm/index.mjs +123 -54
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +181 -87
- package/dist/esm/index.native.js.map +1 -1
- package/package.json +7 -10
- package/src/index.tsx +280 -89
- package/types/index.d.ts +2 -1
- package/types/index.d.ts.map +4 -4
- package/dist/cjs/index.js +0 -198
- package/dist/cjs/index.js.map +0 -6
package/dist/cjs/index.cjs
CHANGED
|
@@ -31,19 +31,24 @@ __export(index_exports, {
|
|
|
31
31
|
measureInWindow: () => measureInWindow,
|
|
32
32
|
measureLayout: () => measureLayout,
|
|
33
33
|
measureNode: () => measureNode,
|
|
34
|
+
registerLayoutNode: () => registerLayoutNode,
|
|
34
35
|
setOnLayoutStrategy: () => setOnLayoutStrategy,
|
|
35
36
|
useElementLayout: () => useElementLayout
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(index_exports);
|
|
38
39
|
var import_constants = require("@tamagui/constants"),
|
|
39
|
-
import_is_equal_shallow = require("@tamagui/is-equal-shallow"),
|
|
40
40
|
import_react = require("react"),
|
|
41
41
|
import_jsx_runtime = require("react/jsx-runtime");
|
|
42
42
|
const LayoutHandlers = /* @__PURE__ */new WeakMap(),
|
|
43
43
|
LayoutDisableKey = /* @__PURE__ */new WeakMap(),
|
|
44
44
|
Nodes = /* @__PURE__ */new Set(),
|
|
45
45
|
IntersectionState = /* @__PURE__ */new WeakMap(),
|
|
46
|
-
|
|
46
|
+
usePretransformDimensions = () => globalThis.__TAMAGUI_ONLAYOUT_PRETRANSFORM === !0 || process.env.TAMAGUI_ONLAYOUT_PRETRANSFORM === "1";
|
|
47
|
+
let _debugLayout;
|
|
48
|
+
function isDebugLayout() {
|
|
49
|
+
return _debugLayout === void 0 && (_debugLayout = typeof window < "u" && new URLSearchParams(window.location.search).has("__tamaDebugLayout")), _debugLayout;
|
|
50
|
+
}
|
|
51
|
+
const DisableLayoutContextValues = {},
|
|
47
52
|
DisableLayoutContextKey = (0, import_react.createContext)(""),
|
|
48
53
|
ENABLE = typeof IntersectionObserver < "u",
|
|
49
54
|
LayoutMeasurementController = ({
|
|
@@ -63,8 +68,7 @@ let globalIntersectionObserver = null,
|
|
|
63
68
|
function setOnLayoutStrategy(state) {
|
|
64
69
|
strategy = state;
|
|
65
70
|
}
|
|
66
|
-
const NodeRectCache = /* @__PURE__ */new WeakMap()
|
|
67
|
-
LastChangeTime = /* @__PURE__ */new WeakMap();
|
|
71
|
+
const NodeRectCache = /* @__PURE__ */new WeakMap();
|
|
68
72
|
let avoidUpdates = !0;
|
|
69
73
|
const queuedUpdates = /* @__PURE__ */new Map();
|
|
70
74
|
function enable() {
|
|
@@ -72,16 +76,33 @@ function enable() {
|
|
|
72
76
|
}
|
|
73
77
|
function startGlobalObservers() {
|
|
74
78
|
!ENABLE || globalIntersectionObserver || (globalIntersectionObserver = new IntersectionObserver(entries => {
|
|
75
|
-
entries.
|
|
76
|
-
const
|
|
79
|
+
for (let i = 0; i < entries.length; i++) {
|
|
80
|
+
const entry = entries[i],
|
|
81
|
+
node = entry.target;
|
|
77
82
|
IntersectionState.get(node) !== entry.isIntersecting && IntersectionState.set(node, entry.isIntersecting);
|
|
78
|
-
}
|
|
83
|
+
}
|
|
79
84
|
}, {
|
|
80
85
|
threshold: 0
|
|
81
86
|
}));
|
|
82
87
|
}
|
|
88
|
+
function rectsEqual(a, b) {
|
|
89
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
90
|
+
}
|
|
83
91
|
if (ENABLE) {
|
|
92
|
+
let ensureRectFetchObserver = function () {
|
|
93
|
+
return rectFetchObserver || (rectFetchObserver = new IntersectionObserver(entries => {
|
|
94
|
+
lastCallbackDelay = Math.round(performance.now() - rectFetchStartTime);
|
|
95
|
+
for (let i = 0; i < entries.length; i++) BoundingRects.set(entries[i].target, entries[i].boundingClientRect);
|
|
96
|
+
process.env.NODE_ENV === "development" && isDebugLayout() && lastCallbackDelay > 50 && console.warn("[onLayout-io-delay]", lastCallbackDelay + "ms", entries.length, "entries"), rectFetchResolve && (rectFetchResolve(!0), rectFetchResolve = null);
|
|
97
|
+
}, {
|
|
98
|
+
threshold: 0
|
|
99
|
+
}), rectFetchObserver);
|
|
100
|
+
};
|
|
84
101
|
const BoundingRects = /* @__PURE__ */new WeakMap();
|
|
102
|
+
let rectFetchObserver = null,
|
|
103
|
+
rectFetchResolve = null,
|
|
104
|
+
rectFetchStartTime = 0,
|
|
105
|
+
lastCallbackDelay = 0;
|
|
85
106
|
async function updateLayoutIfChanged(node) {
|
|
86
107
|
const onLayout = LayoutHandlers.get(node);
|
|
87
108
|
if (typeof onLayout != "function") return;
|
|
@@ -89,68 +110,90 @@ if (ENABLE) {
|
|
|
89
110
|
if (!parentNode) return;
|
|
90
111
|
let nodeRect, parentRect;
|
|
91
112
|
if (strategy === "async") {
|
|
92
|
-
|
|
93
|
-
if (!nr || !pr) return;
|
|
94
|
-
nodeRect = nr, parentRect = pr;
|
|
113
|
+
if (nodeRect = BoundingRects.get(node), parentRect = BoundingRects.get(parentNode), !nodeRect || !parentRect) return;
|
|
95
114
|
} else nodeRect = node.getBoundingClientRect(), parentRect = parentNode.getBoundingClientRect();
|
|
96
|
-
if (!nodeRect || !parentRect) return;
|
|
97
115
|
const cachedRect = NodeRectCache.get(node),
|
|
98
|
-
cachedParentRect = NodeRectCache.get(parentNode)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
!(0, import_is_equal_shallow.isEqualShallow)(cachedRect, nodeRect) ||
|
|
103
|
-
// @ts-expect-error DOMRectReadOnly can go into object
|
|
104
|
-
!(0, import_is_equal_shallow.isEqualShallow)(cachedParentRect, parentRect)) {
|
|
116
|
+
cachedParentRect = NodeRectCache.get(parentNode),
|
|
117
|
+
nodeChanged = !cachedRect || !rectsEqual(cachedRect, nodeRect),
|
|
118
|
+
parentChanged = !cachedParentRect || !rectsEqual(cachedParentRect, parentRect);
|
|
119
|
+
if (nodeChanged || parentChanged) {
|
|
105
120
|
NodeRectCache.set(node, nodeRect), NodeRectCache.set(parentNode, parentRect);
|
|
106
|
-
const event = getElementLayoutEvent(nodeRect, parentRect);
|
|
107
|
-
|
|
121
|
+
const event = getElementLayoutEvent(nodeRect, parentRect, node);
|
|
122
|
+
process.env.NODE_ENV === "development" && isDebugLayout() && console.log("[useElementLayout] change", {
|
|
123
|
+
tag: node.tagName,
|
|
124
|
+
id: node.id || void 0,
|
|
125
|
+
className: (node.className || "").slice(0, 60) || void 0,
|
|
126
|
+
layout: event.nativeEvent.layout,
|
|
127
|
+
first: !cachedRect
|
|
128
|
+
}), avoidUpdates ? queuedUpdates.set(node, () => onLayout(event)) : onLayout(event);
|
|
108
129
|
}
|
|
109
130
|
}
|
|
110
|
-
const
|
|
111
|
-
|
|
131
|
+
const rAF = typeof requestAnimationFrame < "u" ? requestAnimationFrame : void 0,
|
|
132
|
+
userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP,
|
|
133
|
+
BASE_SKIP_FRAMES = userSkipVal ? +userSkipVal : 10,
|
|
134
|
+
MAX_SKIP_FRAMES = 20;
|
|
135
|
+
let skipFrames = BASE_SKIP_FRAMES,
|
|
136
|
+
frameCount = 0;
|
|
112
137
|
async function layoutOnAnimationFrame() {
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (!(node.parentElement instanceof HTMLElement)) continue;
|
|
126
|
-
const disableKey = LayoutDisableKey.get(node);
|
|
127
|
-
disableKey && DisableLayoutContextValues[disableKey] === !0 || IntersectionState.get(node) !== !1 && (didObserve = !0, io.observe(node), io.observe(node.parentElement), visibleNodes.push(node));
|
|
138
|
+
if (frameCount++ % skipFrames !== 0) {
|
|
139
|
+
rAF ? rAF(layoutOnAnimationFrame) : setTimeout(layoutOnAnimationFrame, 16);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (frameCount >= Number.MAX_SAFE_INTEGER && (frameCount = 0), strategy !== "off") {
|
|
143
|
+
const visibleNodes = [],
|
|
144
|
+
parentsToObserve = /* @__PURE__ */new Set();
|
|
145
|
+
for (const node of Nodes) {
|
|
146
|
+
const parentElement = node.parentElement;
|
|
147
|
+
if (!(parentElement instanceof HTMLElement)) {
|
|
148
|
+
cleanupNode(node);
|
|
149
|
+
continue;
|
|
128
150
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
151
|
+
const disableKey = LayoutDisableKey.get(node);
|
|
152
|
+
disableKey && DisableLayoutContextValues[disableKey] === !0 || IntersectionState.get(node) !== !1 && (visibleNodes.push(node), parentsToObserve.add(parentElement));
|
|
153
|
+
}
|
|
154
|
+
if (visibleNodes.length > 0) {
|
|
155
|
+
const io = ensureRectFetchObserver();
|
|
156
|
+
rectFetchStartTime = performance.now();
|
|
157
|
+
for (let i = 0; i < visibleNodes.length; i++) io.observe(visibleNodes[i]);
|
|
158
|
+
for (const parent of parentsToObserve) io.observe(parent);
|
|
159
|
+
await new Promise(res => {
|
|
160
|
+
rectFetchResolve = res;
|
|
161
|
+
});
|
|
162
|
+
for (let i = 0; i < visibleNodes.length; i++) io.unobserve(visibleNodes[i]);
|
|
163
|
+
for (const parent of parentsToObserve) io.unobserve(parent);
|
|
164
|
+
lastCallbackDelay > 50 ? skipFrames = Math.min(skipFrames + 2, MAX_SKIP_FRAMES) : lastCallbackDelay < 20 && (skipFrames = Math.max(skipFrames - 1, BASE_SKIP_FRAMES));
|
|
165
|
+
for (let i = 0; i < visibleNodes.length; i++) updateLayoutIfChanged(visibleNodes[i]);
|
|
166
|
+
}
|
|
133
167
|
}
|
|
134
|
-
setTimeout(layoutOnAnimationFrame, 16
|
|
168
|
+
rAF ? rAF(layoutOnAnimationFrame) : setTimeout(layoutOnAnimationFrame, 16);
|
|
135
169
|
}
|
|
136
170
|
layoutOnAnimationFrame();
|
|
137
171
|
}
|
|
138
|
-
const getElementLayoutEvent = (nodeRect, parentRect) => ({
|
|
172
|
+
const getElementLayoutEvent = (nodeRect, parentRect, node) => ({
|
|
139
173
|
nativeEvent: {
|
|
140
|
-
layout: getRelativeDimensions(nodeRect, parentRect),
|
|
174
|
+
layout: getRelativeDimensions(nodeRect, parentRect, node),
|
|
141
175
|
target: nodeRect
|
|
142
176
|
},
|
|
143
177
|
timeStamp: Date.now()
|
|
144
178
|
}),
|
|
145
|
-
|
|
179
|
+
getPreTransformDimensions = node => ({
|
|
180
|
+
width: node.offsetWidth,
|
|
181
|
+
height: node.offsetHeight
|
|
182
|
+
}),
|
|
183
|
+
getRelativeDimensions = (a, b, aNode) => {
|
|
146
184
|
const {
|
|
147
|
-
height,
|
|
148
185
|
left,
|
|
149
|
-
top
|
|
150
|
-
width
|
|
186
|
+
top
|
|
151
187
|
} = a,
|
|
152
188
|
x = left - b.left,
|
|
153
|
-
y = top - b.top
|
|
189
|
+
y = top - b.top,
|
|
190
|
+
{
|
|
191
|
+
width,
|
|
192
|
+
height
|
|
193
|
+
} = usePretransformDimensions() && aNode ? getPreTransformDimensions(aNode) : {
|
|
194
|
+
width: a.width,
|
|
195
|
+
height: a.height
|
|
196
|
+
};
|
|
154
197
|
return {
|
|
155
198
|
x,
|
|
156
199
|
y,
|
|
@@ -160,17 +203,44 @@ const getElementLayoutEvent = (nodeRect, parentRect) => ({
|
|
|
160
203
|
pageY: a.top
|
|
161
204
|
};
|
|
162
205
|
};
|
|
206
|
+
function registerLayoutNode(node, onChange, disableKey) {
|
|
207
|
+
return Nodes.add(node), LayoutHandlers.set(node, onChange), disableKey && LayoutDisableKey.set(node, disableKey), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(node), IntersectionState.set(node, !0)), () => cleanupNode(node);
|
|
208
|
+
}
|
|
209
|
+
function cleanupNode(node) {
|
|
210
|
+
Nodes.delete(node), LayoutHandlers.delete(node), LayoutDisableKey.delete(node), NodeRectCache.delete(node), IntersectionState.delete(node), globalIntersectionObserver && globalIntersectionObserver.unobserve(node);
|
|
211
|
+
}
|
|
212
|
+
const PrevHostNode = /* @__PURE__ */new WeakMap();
|
|
163
213
|
function useElementLayout(ref, onLayout) {
|
|
164
214
|
const disableKey = (0, import_react.useContext)(DisableLayoutContextKey),
|
|
165
215
|
node = ensureWebElement(ref.current?.host);
|
|
166
216
|
node && onLayout && (LayoutHandlers.set(node, onLayout), LayoutDisableKey.set(node, disableKey)), (0, import_constants.useIsomorphicLayoutEffect)(() => {
|
|
217
|
+
if (!onLayout) return;
|
|
218
|
+
const nextNode = ensureWebElement(ref.current?.host),
|
|
219
|
+
prevNode = PrevHostNode.get(ref);
|
|
220
|
+
if (nextNode === prevNode || (prevNode && cleanupNode(prevNode), PrevHostNode.set(ref, nextNode), !nextNode)) return;
|
|
221
|
+
Nodes.add(nextNode), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(nextNode), IntersectionState.set(nextNode, !0));
|
|
222
|
+
const handler = LayoutHandlers.get(nextNode);
|
|
223
|
+
if (typeof handler != "function") return;
|
|
224
|
+
const parentNode = nextNode.parentElement;
|
|
225
|
+
if (!parentNode) return;
|
|
226
|
+
const nodeRect = nextNode.getBoundingClientRect(),
|
|
227
|
+
parentRect = parentNode.getBoundingClientRect();
|
|
228
|
+
NodeRectCache.set(nextNode, nodeRect), NodeRectCache.set(parentNode, parentRect), handler(getElementLayoutEvent(nodeRect, parentRect, nextNode));
|
|
229
|
+
}), (0, import_constants.useIsomorphicLayoutEffect)(() => {
|
|
167
230
|
if (!onLayout) return;
|
|
168
231
|
const node2 = ref.current?.host;
|
|
169
232
|
if (!node2) return;
|
|
170
|
-
Nodes.add(node2), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(node2), IntersectionState.set(node2, !0))
|
|
233
|
+
Nodes.add(node2), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(node2), IntersectionState.set(node2, !0)), process.env.NODE_ENV === "development" && isDebugLayout() && console.log("[useElementLayout] register", {
|
|
234
|
+
tag: node2.tagName,
|
|
235
|
+
id: node2.id || void 0,
|
|
236
|
+
className: (node2.className || "").slice(0, 60) || void 0,
|
|
237
|
+
totalNodes: Nodes.size
|
|
238
|
+
});
|
|
171
239
|
const parentNode = node2.parentNode;
|
|
172
|
-
return parentNode && onLayout(getElementLayoutEvent(node2.getBoundingClientRect(), parentNode.getBoundingClientRect())), () => {
|
|
173
|
-
|
|
240
|
+
return parentNode && onLayout(getElementLayoutEvent(node2.getBoundingClientRect(), parentNode.getBoundingClientRect(), node2)), () => {
|
|
241
|
+
cleanupNode(node2);
|
|
242
|
+
const swappedNode = PrevHostNode.get(ref);
|
|
243
|
+
swappedNode && swappedNode !== node2 && cleanupNode(swappedNode), PrevHostNode.delete(ref);
|
|
174
244
|
};
|
|
175
245
|
}, [ref, !!onLayout]);
|
|
176
246
|
}
|
|
@@ -188,7 +258,7 @@ const getBoundingClientRectAsync = node => new Promise(res => {
|
|
|
188
258
|
const relativeNode = relativeTo || node?.parentElement;
|
|
189
259
|
if (relativeNode instanceof HTMLElement) {
|
|
190
260
|
const [nodeDim, relativeNodeDim] = await Promise.all([getBoundingClientRectAsync(node), getBoundingClientRectAsync(relativeNode)]);
|
|
191
|
-
if (relativeNodeDim && nodeDim) return getRelativeDimensions(nodeDim, relativeNodeDim);
|
|
261
|
+
if (relativeNodeDim && nodeDim) return getRelativeDimensions(nodeDim, relativeNodeDim, node);
|
|
192
262
|
}
|
|
193
263
|
return null;
|
|
194
264
|
},
|
package/dist/cjs/index.native.js
CHANGED
|
@@ -33,13 +33,13 @@ __export(index_exports, {
|
|
|
33
33
|
measureInWindow: () => measureInWindow,
|
|
34
34
|
measureLayout: () => measureLayout,
|
|
35
35
|
measureNode: () => measureNode,
|
|
36
|
+
registerLayoutNode: () => registerLayoutNode,
|
|
36
37
|
setOnLayoutStrategy: () => setOnLayoutStrategy,
|
|
37
38
|
useElementLayout: () => useElementLayout
|
|
38
39
|
});
|
|
39
40
|
module.exports = __toCommonJS(index_exports);
|
|
40
41
|
var import_jsx_runtime = require("react/jsx-runtime"),
|
|
41
42
|
import_constants = require("@tamagui/constants"),
|
|
42
|
-
import_is_equal_shallow = require("@tamagui/is-equal-shallow"),
|
|
43
43
|
import_react = require("react");
|
|
44
44
|
function _instanceof(left, right) {
|
|
45
45
|
return right != null && typeof Symbol < "u" && right[Symbol.hasInstance] ? !!right[Symbol.hasInstance](left) : left instanceof right;
|
|
@@ -48,7 +48,14 @@ var LayoutHandlers = /* @__PURE__ */new WeakMap(),
|
|
|
48
48
|
LayoutDisableKey = /* @__PURE__ */new WeakMap(),
|
|
49
49
|
Nodes = /* @__PURE__ */new Set(),
|
|
50
50
|
IntersectionState = /* @__PURE__ */new WeakMap(),
|
|
51
|
-
|
|
51
|
+
usePretransformDimensions = function () {
|
|
52
|
+
return globalThis.__TAMAGUI_ONLAYOUT_PRETRANSFORM === !0 || process.env.TAMAGUI_ONLAYOUT_PRETRANSFORM === "1";
|
|
53
|
+
},
|
|
54
|
+
_debugLayout;
|
|
55
|
+
function isDebugLayout() {
|
|
56
|
+
return _debugLayout === void 0 && (_debugLayout = typeof window < "u" && new URLSearchParams(window.location.search).has("__tamaDebugLayout")), _debugLayout;
|
|
57
|
+
}
|
|
58
|
+
var DisableLayoutContextValues = {},
|
|
52
59
|
DisableLayoutContextKey = /* @__PURE__ */(0, import_react.createContext)(""),
|
|
53
60
|
ENABLE = !1,
|
|
54
61
|
LayoutMeasurementController = function (param) {
|
|
@@ -70,7 +77,6 @@ function setOnLayoutStrategy(state) {
|
|
|
70
77
|
strategy = state;
|
|
71
78
|
}
|
|
72
79
|
var NodeRectCache = /* @__PURE__ */new WeakMap(),
|
|
73
|
-
LastChangeTime = /* @__PURE__ */new WeakMap(),
|
|
74
80
|
avoidUpdates = !0,
|
|
75
81
|
queuedUpdates = /* @__PURE__ */new Map();
|
|
76
82
|
function enable() {
|
|
@@ -80,16 +86,34 @@ function enable() {
|
|
|
80
86
|
}
|
|
81
87
|
function startGlobalObservers() {
|
|
82
88
|
!ENABLE || globalIntersectionObserver || (globalIntersectionObserver = new IntersectionObserver(function (entries) {
|
|
83
|
-
entries.
|
|
84
|
-
var
|
|
89
|
+
for (var i = 0; i < entries.length; i++) {
|
|
90
|
+
var entry = entries[i],
|
|
91
|
+
node = entry.target;
|
|
85
92
|
IntersectionState.get(node) !== entry.isIntersecting && IntersectionState.set(node, entry.isIntersecting);
|
|
86
|
-
}
|
|
93
|
+
}
|
|
87
94
|
}, {
|
|
88
95
|
threshold: 0
|
|
89
96
|
}));
|
|
90
97
|
}
|
|
98
|
+
function rectsEqual(a, b) {
|
|
99
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
100
|
+
}
|
|
91
101
|
if (ENABLE) {
|
|
92
|
-
|
|
102
|
+
let ensureRectFetchObserver = function () {
|
|
103
|
+
return rectFetchObserver || (rectFetchObserver = new IntersectionObserver(function (entries) {
|
|
104
|
+
lastCallbackDelay = Math.round(performance.now() - rectFetchStartTime);
|
|
105
|
+
for (var i = 0; i < entries.length; i++) BoundingRects.set(entries[i].target, entries[i].boundingClientRect);
|
|
106
|
+
process.env.NODE_ENV === "development" && isDebugLayout() && lastCallbackDelay > 50 && console.warn("[onLayout-io-delay]", lastCallbackDelay + "ms", entries.length, "entries"), rectFetchResolve && (rectFetchResolve(!0), rectFetchResolve = null);
|
|
107
|
+
}, {
|
|
108
|
+
threshold: 0
|
|
109
|
+
}), rectFetchObserver);
|
|
110
|
+
};
|
|
111
|
+
var ensureRectFetchObserver2 = ensureRectFetchObserver,
|
|
112
|
+
BoundingRects = /* @__PURE__ */new WeakMap(),
|
|
113
|
+
rectFetchObserver = null,
|
|
114
|
+
rectFetchResolve = null,
|
|
115
|
+
rectFetchStartTime = 0,
|
|
116
|
+
lastCallbackDelay = 0;
|
|
93
117
|
async function updateLayoutIfChanged(node) {
|
|
94
118
|
var onLayout = LayoutHandlers.get(node);
|
|
95
119
|
if (typeof onLayout == "function") {
|
|
@@ -97,107 +121,144 @@ if (ENABLE) {
|
|
|
97
121
|
if (parentNode) {
|
|
98
122
|
var nodeRect, parentRect;
|
|
99
123
|
if (strategy === "async") {
|
|
100
|
-
|
|
101
|
-
if (!nr || !pr) return;
|
|
102
|
-
nodeRect = nr, parentRect = pr;
|
|
124
|
+
if (nodeRect = BoundingRects.get(node), parentRect = BoundingRects.get(parentNode), !nodeRect || !parentRect) return;
|
|
103
125
|
} else nodeRect = node.getBoundingClientRect(), parentRect = parentNode.getBoundingClientRect();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
var cachedRect = NodeRectCache.get(node),
|
|
127
|
+
cachedParentRect = NodeRectCache.get(parentNode),
|
|
128
|
+
nodeChanged = !cachedRect || !rectsEqual(cachedRect, nodeRect),
|
|
129
|
+
parentChanged = !cachedParentRect || !rectsEqual(cachedParentRect, parentRect);
|
|
130
|
+
if (nodeChanged || parentChanged) {
|
|
131
|
+
NodeRectCache.set(node, nodeRect), NodeRectCache.set(parentNode, parentRect);
|
|
132
|
+
var event = getElementLayoutEvent(nodeRect, parentRect, node);
|
|
133
|
+
process.env.NODE_ENV === "development" && isDebugLayout() && console.log("[useElementLayout] change", {
|
|
134
|
+
tag: node.tagName,
|
|
135
|
+
id: node.id || void 0,
|
|
136
|
+
className: (node.className || "").slice(0, 60) || void 0,
|
|
137
|
+
layout: event.nativeEvent.layout,
|
|
138
|
+
first: !cachedRect
|
|
139
|
+
}), avoidUpdates ? queuedUpdates.set(node, function () {
|
|
140
|
+
return onLayout(event);
|
|
141
|
+
}) : onLayout(event);
|
|
119
142
|
}
|
|
120
143
|
}
|
|
121
144
|
}
|
|
122
145
|
}
|
|
123
|
-
var
|
|
124
|
-
|
|
146
|
+
var rAF = typeof requestAnimationFrame < "u" ? requestAnimationFrame : void 0,
|
|
147
|
+
userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP,
|
|
148
|
+
BASE_SKIP_FRAMES = userSkipVal ? +userSkipVal : 10,
|
|
149
|
+
MAX_SKIP_FRAMES = 20,
|
|
150
|
+
skipFrames = BASE_SKIP_FRAMES,
|
|
151
|
+
frameCount = 0;
|
|
125
152
|
async function layoutOnAnimationFrame() {
|
|
126
|
-
if (
|
|
153
|
+
if (frameCount++ % skipFrames !== 0) {
|
|
154
|
+
rAF ? rAF(layoutOnAnimationFrame) : setTimeout(layoutOnAnimationFrame, 16);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (frameCount >= Number.MAX_SAFE_INTEGER && (frameCount = 0), strategy !== "off") {
|
|
127
158
|
var visibleNodes = [],
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
parentsToObserve = /* @__PURE__ */new Set(),
|
|
160
|
+
_iteratorNormalCompletion = !0,
|
|
161
|
+
_didIteratorError = !1,
|
|
162
|
+
_iteratorError = void 0;
|
|
163
|
+
try {
|
|
164
|
+
for (var _iterator = Nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = !0) {
|
|
165
|
+
var node = _step.value,
|
|
166
|
+
parentElement = node.parentElement;
|
|
167
|
+
if (!_instanceof(parentElement, HTMLElement)) {
|
|
168
|
+
cleanupNode(node);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
var disableKey = LayoutDisableKey.get(node);
|
|
172
|
+
disableKey && DisableLayoutContextValues[disableKey] === !0 || IntersectionState.get(node) !== !1 && (visibleNodes.push(node), parentsToObserve.add(parentElement));
|
|
173
|
+
}
|
|
174
|
+
} catch (err) {
|
|
175
|
+
_didIteratorError = !0, _iteratorError = err;
|
|
176
|
+
} finally {
|
|
177
|
+
try {
|
|
178
|
+
!_iteratorNormalCompletion && _iterator.return != null && _iterator.return();
|
|
179
|
+
} finally {
|
|
180
|
+
if (_didIteratorError) throw _iteratorError;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (visibleNodes.length > 0) {
|
|
184
|
+
var io = ensureRectFetchObserver();
|
|
185
|
+
rectFetchStartTime = performance.now();
|
|
186
|
+
for (var i = 0; i < visibleNodes.length; i++) io.observe(visibleNodes[i]);
|
|
187
|
+
var _iteratorNormalCompletion1 = !0,
|
|
188
|
+
_didIteratorError1 = !1,
|
|
189
|
+
_iteratorError1 = void 0;
|
|
190
|
+
try {
|
|
191
|
+
for (var _iterator1 = parentsToObserve[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = !0) {
|
|
192
|
+
var parent = _step1.value;
|
|
193
|
+
io.observe(parent);
|
|
194
|
+
}
|
|
195
|
+
} catch (err) {
|
|
196
|
+
_didIteratorError1 = !0, _iteratorError1 = err;
|
|
197
|
+
} finally {
|
|
156
198
|
try {
|
|
157
|
-
|
|
158
|
-
var node = _step.value;
|
|
159
|
-
if (_instanceof(node.parentElement, HTMLElement)) {
|
|
160
|
-
var disableKey = LayoutDisableKey.get(node);
|
|
161
|
-
disableKey && DisableLayoutContextValues[disableKey] === !0 || IntersectionState.get(node) !== !1 && (didObserve = !0, io.observe(node), io.observe(node.parentElement), visibleNodes.push(node));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
} catch (err) {
|
|
165
|
-
_didIteratorError = !0, _iteratorError = err;
|
|
199
|
+
!_iteratorNormalCompletion1 && _iterator1.return != null && _iterator1.return();
|
|
166
200
|
} finally {
|
|
167
|
-
|
|
168
|
-
!_iteratorNormalCompletion && _iterator.return != null && _iterator.return();
|
|
169
|
-
} finally {
|
|
170
|
-
if (_didIteratorError) throw _iteratorError;
|
|
171
|
-
}
|
|
201
|
+
if (_didIteratorError1) throw _iteratorError1;
|
|
172
202
|
}
|
|
173
|
-
|
|
203
|
+
}
|
|
204
|
+
await new Promise(function (res) {
|
|
205
|
+
rectFetchResolve = res;
|
|
174
206
|
});
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
207
|
+
for (var i1 = 0; i1 < visibleNodes.length; i1++) io.unobserve(visibleNodes[i1]);
|
|
208
|
+
var _iteratorNormalCompletion2 = !0,
|
|
209
|
+
_didIteratorError2 = !1,
|
|
210
|
+
_iteratorError2 = void 0;
|
|
211
|
+
try {
|
|
212
|
+
for (var _iterator2 = parentsToObserve[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = !0) {
|
|
213
|
+
var parent1 = _step2.value;
|
|
214
|
+
io.unobserve(parent1);
|
|
215
|
+
}
|
|
216
|
+
} catch (err) {
|
|
217
|
+
_didIteratorError2 = !0, _iteratorError2 = err;
|
|
218
|
+
} finally {
|
|
219
|
+
try {
|
|
220
|
+
!_iteratorNormalCompletion2 && _iterator2.return != null && _iterator2.return();
|
|
221
|
+
} finally {
|
|
222
|
+
if (_didIteratorError2) throw _iteratorError2;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
lastCallbackDelay > 50 ? skipFrames = Math.min(skipFrames + 2, MAX_SKIP_FRAMES) : lastCallbackDelay < 20 && (skipFrames = Math.max(skipFrames - 1, BASE_SKIP_FRAMES));
|
|
226
|
+
for (var i2 = 0; i2 < visibleNodes.length; i2++) updateLayoutIfChanged(visibleNodes[i2]);
|
|
227
|
+
}
|
|
178
228
|
}
|
|
179
|
-
setTimeout(layoutOnAnimationFrame, 16
|
|
229
|
+
rAF ? rAF(layoutOnAnimationFrame) : setTimeout(layoutOnAnimationFrame, 16);
|
|
180
230
|
}
|
|
181
231
|
layoutOnAnimationFrame();
|
|
182
232
|
}
|
|
183
|
-
var getElementLayoutEvent = function (nodeRect, parentRect) {
|
|
233
|
+
var getElementLayoutEvent = function (nodeRect, parentRect, node) {
|
|
184
234
|
return {
|
|
185
235
|
nativeEvent: {
|
|
186
|
-
layout: getRelativeDimensions(nodeRect, parentRect),
|
|
236
|
+
layout: getRelativeDimensions(nodeRect, parentRect, node),
|
|
187
237
|
target: nodeRect
|
|
188
238
|
},
|
|
189
239
|
timeStamp: Date.now()
|
|
190
240
|
};
|
|
191
241
|
},
|
|
192
|
-
|
|
242
|
+
getPreTransformDimensions = function (node) {
|
|
243
|
+
return {
|
|
244
|
+
width: node.offsetWidth,
|
|
245
|
+
height: node.offsetHeight
|
|
246
|
+
};
|
|
247
|
+
},
|
|
248
|
+
getRelativeDimensions = function (a, b, aNode) {
|
|
193
249
|
var {
|
|
194
|
-
height,
|
|
195
250
|
left,
|
|
196
|
-
top
|
|
197
|
-
width
|
|
251
|
+
top
|
|
198
252
|
} = a,
|
|
199
253
|
x = left - b.left,
|
|
200
|
-
y = top - b.top
|
|
254
|
+
y = top - b.top,
|
|
255
|
+
{
|
|
256
|
+
width,
|
|
257
|
+
height
|
|
258
|
+
} = usePretransformDimensions() && aNode ? getPreTransformDimensions(aNode) : {
|
|
259
|
+
width: a.width,
|
|
260
|
+
height: a.height
|
|
261
|
+
};
|
|
201
262
|
return {
|
|
202
263
|
x,
|
|
203
264
|
y,
|
|
@@ -207,19 +268,53 @@ var getElementLayoutEvent = function (nodeRect, parentRect) {
|
|
|
207
268
|
pageY: a.top
|
|
208
269
|
};
|
|
209
270
|
};
|
|
271
|
+
function registerLayoutNode(node, onChange, disableKey) {
|
|
272
|
+
return Nodes.add(node), LayoutHandlers.set(node, onChange), disableKey && LayoutDisableKey.set(node, disableKey), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(node), IntersectionState.set(node, !0)), function () {
|
|
273
|
+
return cleanupNode(node);
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function cleanupNode(node) {
|
|
277
|
+
Nodes.delete(node), LayoutHandlers.delete(node), LayoutDisableKey.delete(node), NodeRectCache.delete(node), IntersectionState.delete(node), globalIntersectionObserver && globalIntersectionObserver.unobserve(node);
|
|
278
|
+
}
|
|
279
|
+
var PrevHostNode = /* @__PURE__ */new WeakMap();
|
|
210
280
|
function useElementLayout(ref, onLayout) {
|
|
211
281
|
var _ref_current,
|
|
212
282
|
disableKey = (0, import_react.useContext)(DisableLayoutContextKey),
|
|
213
283
|
node = ensureWebElement((_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.host);
|
|
214
284
|
node && onLayout && (LayoutHandlers.set(node, onLayout), LayoutDisableKey.set(node, disableKey)), (0, import_constants.useIsomorphicLayoutEffect)(function () {
|
|
285
|
+
var _ref_current2;
|
|
286
|
+
if (onLayout) {
|
|
287
|
+
var nextNode = ensureWebElement((_ref_current2 = ref.current) === null || _ref_current2 === void 0 ? void 0 : _ref_current2.host),
|
|
288
|
+
prevNode = PrevHostNode.get(ref);
|
|
289
|
+
if (nextNode !== prevNode && (prevNode && cleanupNode(prevNode), PrevHostNode.set(ref, nextNode), !!nextNode)) {
|
|
290
|
+
Nodes.add(nextNode), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(nextNode), IntersectionState.set(nextNode, !0));
|
|
291
|
+
var handler = LayoutHandlers.get(nextNode);
|
|
292
|
+
if (typeof handler == "function") {
|
|
293
|
+
var parentNode = nextNode.parentElement;
|
|
294
|
+
if (parentNode) {
|
|
295
|
+
var nodeRect = nextNode.getBoundingClientRect(),
|
|
296
|
+
parentRect = parentNode.getBoundingClientRect();
|
|
297
|
+
NodeRectCache.set(nextNode, nodeRect), NodeRectCache.set(parentNode, parentRect), handler(getElementLayoutEvent(nodeRect, parentRect, nextNode));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}), (0, import_constants.useIsomorphicLayoutEffect)(function () {
|
|
215
303
|
var _ref_current2;
|
|
216
304
|
if (onLayout) {
|
|
217
305
|
var node2 = (_ref_current2 = ref.current) === null || _ref_current2 === void 0 ? void 0 : _ref_current2.host;
|
|
218
306
|
if (node2) {
|
|
219
|
-
Nodes.add(node2), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(node2), IntersectionState.set(node2, !0))
|
|
307
|
+
Nodes.add(node2), startGlobalObservers(), globalIntersectionObserver && (globalIntersectionObserver.observe(node2), IntersectionState.set(node2, !0)), process.env.NODE_ENV === "development" && isDebugLayout() && console.log("[useElementLayout] register", {
|
|
308
|
+
tag: node2.tagName,
|
|
309
|
+
id: node2.id || void 0,
|
|
310
|
+
className: (node2.className || "").slice(0, 60) || void 0,
|
|
311
|
+
totalNodes: Nodes.size
|
|
312
|
+
});
|
|
220
313
|
var parentNode = node2.parentNode;
|
|
221
|
-
return parentNode && onLayout(getElementLayoutEvent(node2.getBoundingClientRect(), parentNode.getBoundingClientRect())), function () {
|
|
222
|
-
|
|
314
|
+
return parentNode && onLayout(getElementLayoutEvent(node2.getBoundingClientRect(), parentNode.getBoundingClientRect(), node2)), function () {
|
|
315
|
+
cleanupNode(node2);
|
|
316
|
+
var swappedNode = PrevHostNode.get(ref);
|
|
317
|
+
swappedNode && swappedNode !== node2 && cleanupNode(swappedNode), PrevHostNode.delete(ref);
|
|
223
318
|
};
|
|
224
319
|
}
|
|
225
320
|
}
|
|
@@ -243,7 +338,7 @@ var getBoundingClientRectAsync = function (node) {
|
|
|
243
338
|
var relativeNode = relativeTo || node?.parentElement;
|
|
244
339
|
if (_instanceof(relativeNode, HTMLElement)) {
|
|
245
340
|
var [nodeDim, relativeNodeDim] = await Promise.all([getBoundingClientRectAsync(node), getBoundingClientRectAsync(relativeNode)]);
|
|
246
|
-
if (relativeNodeDim && nodeDim) return getRelativeDimensions(nodeDim, relativeNodeDim);
|
|
341
|
+
if (relativeNodeDim && nodeDim) return getRelativeDimensions(nodeDim, relativeNodeDim, node);
|
|
247
342
|
}
|
|
248
343
|
return null;
|
|
249
344
|
},
|