@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.
@@ -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
- DisableLayoutContextValues = {},
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.forEach(entry => {
76
- const node = entry.target;
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
- const [nr, pr] = await Promise.all([BoundingRects.get(node), BoundingRects.get(parentNode)]);
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
- if (!cachedRect || !cachedParentRect ||
100
- // has changed one rect
101
- // @ts-expect-error DOMRectReadOnly can go into object
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
- avoidUpdates ? queuedUpdates.set(node, () => onLayout(event)) : onLayout(event);
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 userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP,
111
- RUN_EVERY_X_FRAMES = userSkipVal ? +userSkipVal : 14;
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 (strategy !== "off") {
114
- const visibleNodes = [];
115
- (await new Promise(res => {
116
- const io = new IntersectionObserver(entries => {
117
- io.disconnect();
118
- for (const entry of entries) BoundingRects.set(entry.target, entry.boundingClientRect);
119
- res(!0);
120
- }, {
121
- threshold: 0
122
- });
123
- let didObserve = !1;
124
- for (const node of Nodes) {
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
- didObserve || res(!1);
130
- })) && visibleNodes.forEach(node => {
131
- updateLayoutIfChanged(node);
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.6667 * RUN_EVERY_X_FRAMES);
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
- getRelativeDimensions = (a, b) => {
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
- Nodes.delete(node2), LayoutHandlers.delete(node2), NodeRectCache.delete(node2), LastChangeTime.delete(node2), IntersectionState.delete(node2), globalIntersectionObserver && globalIntersectionObserver.unobserve(node2);
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
  },
@@ -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
- DisableLayoutContextValues = {},
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.forEach(function (entry) {
84
- var node = entry.target;
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
- var BoundingRects = /* @__PURE__ */new WeakMap();
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
- var [nr, pr] = await Promise.all([BoundingRects.get(node), BoundingRects.get(parentNode)]);
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
- if (!(!nodeRect || !parentRect)) {
105
- var cachedRect = NodeRectCache.get(node),
106
- cachedParentRect = NodeRectCache.get(parentNode);
107
- if (!cachedRect || !cachedParentRect ||
108
- // has changed one rect
109
- // @ts-expect-error DOMRectReadOnly can go into object
110
- !(0, import_is_equal_shallow.isEqualShallow)(cachedRect, nodeRect) ||
111
- // @ts-expect-error DOMRectReadOnly can go into object
112
- !(0, import_is_equal_shallow.isEqualShallow)(cachedParentRect, parentRect)) {
113
- NodeRectCache.set(node, nodeRect), NodeRectCache.set(parentNode, parentRect);
114
- var event = getElementLayoutEvent(nodeRect, parentRect);
115
- avoidUpdates ? queuedUpdates.set(node, function () {
116
- return onLayout(event);
117
- }) : onLayout(event);
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 userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP,
124
- RUN_EVERY_X_FRAMES = userSkipVal ? +userSkipVal : 14;
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 (strategy !== "off") {
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
- didRun = await new Promise(function (res) {
129
- var io = new IntersectionObserver(function (entries) {
130
- io.disconnect();
131
- var _iteratorNormalCompletion2 = !0,
132
- _didIteratorError2 = !1,
133
- _iteratorError2 = void 0;
134
- try {
135
- for (var _iterator2 = entries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = !0) {
136
- var entry = _step2.value;
137
- BoundingRects.set(entry.target, entry.boundingClientRect);
138
- }
139
- } catch (err) {
140
- _didIteratorError2 = !0, _iteratorError2 = err;
141
- } finally {
142
- try {
143
- !_iteratorNormalCompletion2 && _iterator2.return != null && _iterator2.return();
144
- } finally {
145
- if (_didIteratorError2) throw _iteratorError2;
146
- }
147
- }
148
- res(!0);
149
- }, {
150
- threshold: 0
151
- }),
152
- didObserve = !1,
153
- _iteratorNormalCompletion = !0,
154
- _didIteratorError = !1,
155
- _iteratorError = void 0;
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
- for (var _iterator = Nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = !0) {
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
- try {
168
- !_iteratorNormalCompletion && _iterator.return != null && _iterator.return();
169
- } finally {
170
- if (_didIteratorError) throw _iteratorError;
171
- }
201
+ if (_didIteratorError1) throw _iteratorError1;
172
202
  }
173
- didObserve || res(!1);
203
+ }
204
+ await new Promise(function (res) {
205
+ rectFetchResolve = res;
174
206
  });
175
- didRun && visibleNodes.forEach(function (node) {
176
- updateLayoutIfChanged(node);
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.6667 * RUN_EVERY_X_FRAMES);
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
- getRelativeDimensions = function (a, b) {
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
- Nodes.delete(node2), LayoutHandlers.delete(node2), NodeRectCache.delete(node2), LastChangeTime.delete(node2), IntersectionState.delete(node2), globalIntersectionObserver && globalIntersectionObserver.unobserve(node2);
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
  },