@tamagui/use-element-layout 2.7.7 → 3.0.0-beta.1091.1

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/src/index.tsx CHANGED
@@ -4,35 +4,22 @@ import { createContext, useContext, useId, type ReactNode, type RefObject } from
4
4
  const LayoutHandlers = new WeakMap<HTMLElement, Function>()
5
5
  const LayoutDisableKey = new WeakMap<HTMLElement, string>()
6
6
  const Nodes = new Set<HTMLElement>()
7
+ const NodeRectCache = new WeakMap<HTMLElement, DOMRectReadOnly>()
8
+ const PrevHostNode = new WeakMap<object, HTMLElement | undefined>()
7
9
 
8
- // feature flag to enable pre-transform dimension reporting (matches RN behavior)
9
- // can be set via env var at build time or runtime global for testing
10
- // see: https://github.com/tamagui/tamagui/pull/2329
11
10
  const usePretransformDimensions = () =>
12
11
  (globalThis as any).__TAMAGUI_ONLAYOUT_PRETRANSFORM === true ||
13
12
  process.env.TAMAGUI_ONLAYOUT_PRETRANSFORM === '1'
14
13
 
15
- let _debugLayout: boolean | undefined
16
-
17
- function isDebugLayout() {
18
- if (_debugLayout === undefined) {
19
- _debugLayout =
20
- typeof window !== 'undefined' &&
21
- new URLSearchParams(window.location.search).has('__tamaDebugLayout')
22
- }
23
- return _debugLayout
24
- }
14
+ const isDebugLayout = () =>
15
+ typeof window !== 'undefined' && window.location?.search?.includes('__tamaDebugLayout')
25
16
 
26
- // separating to avoid all re-rendering
27
17
  const DisableLayoutContextValues: Record<string, boolean> = {}
28
18
  const DisableLayoutContextKey = createContext<string>('')
29
19
 
30
20
  const ENABLE =
31
21
  process.env.TAMAGUI_TARGET === 'web' && typeof IntersectionObserver !== 'undefined'
32
22
 
33
- // internal testing - advanced helper to turn off layout measurement for extra performance
34
- // TODO document!
35
- // TODO could add frame skip control here
36
23
  export const LayoutMeasurementController = ({
37
24
  disable,
38
25
  children,
@@ -41,16 +28,10 @@ export const LayoutMeasurementController = ({
41
28
  children: ReactNode
42
29
  }): ReactNode => {
43
30
  const id = useId()
44
-
45
31
  useIsomorphicLayoutEffect(() => {
46
32
  const wasDisabled = DisableLayoutContextValues[id] === true
47
33
  DisableLayoutContextValues[id] = disable
48
- // a controller flipping to enabled (a sheet or popper opening) is often
49
- // waiting on a measurement to position itself, so don't make it sit out
50
- // the frame-skip window
51
- if (wasDisabled && !disable) {
52
- measureOnNextFrame?.()
53
- }
34
+ if (wasDisabled && !disable) measureOnNextFrame?.()
54
35
  }, [disable, id])
55
36
 
56
37
  return (
@@ -60,29 +41,13 @@ export const LayoutMeasurementController = ({
60
41
  )
61
42
  }
62
43
 
63
- type TamaguiComponentStatePartial = {
64
- host?: any
65
- }
66
-
44
+ type TamaguiComponentStatePartial = { host?: any }
67
45
  type LayoutMeasurementStrategy = 'off' | 'sync' | 'async'
68
46
 
69
47
  let strategy: LayoutMeasurementStrategy = 'async'
70
-
71
- // the measurement loop parks itself whenever it provably has nothing to do: no
72
- // registered nodes, a hidden document, or measurement turned off. these are the
73
- // only three ways work can reappear, so each one restarts it.
74
48
  let resumeLayoutLoop: (() => void) | undefined
75
-
76
- // restarts the loop AND makes its next frame a measuring frame, skipping the
77
- // frame-skip backoff once. for consumers whose position depends on a pending
78
- // measurement (an opening sheet parked off-screen).
79
49
  let measureOnNextFrame: (() => void) | undefined
80
50
 
81
- export function setOnLayoutStrategy(state: LayoutMeasurementStrategy): void {
82
- strategy = state
83
- resumeLayoutLoop?.()
84
- }
85
-
86
51
  export type LayoutValue = {
87
52
  x: number
88
53
  y: number
@@ -93,16 +58,10 @@ export type LayoutValue = {
93
58
  }
94
59
 
95
60
  export type LayoutEvent = {
96
- nativeEvent: {
97
- layout: LayoutValue
98
- target: any
99
- }
61
+ nativeEvent: { layout: LayoutValue; target: any }
100
62
  timeStamp: number
101
63
  }
102
64
 
103
- const NodeRectCache = new WeakMap<HTMLElement, DOMRectReadOnly>()
104
-
105
- // prevent thrashing during first hydration (somewhat, streaming gets trickier)
106
65
  let avoidUpdates = true
107
66
  const queuedUpdates = new Map<HTMLElement, Function>()
108
67
 
@@ -116,15 +75,12 @@ export function enable(): void {
116
75
  }
117
76
  }
118
77
 
119
- // optimization: inline rect comparison to avoid function call overhead on hot path
120
78
  function rectsEqual(a: DOMRectReadOnly, b: DOMRectReadOnly): boolean {
121
79
  return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height
122
80
  }
123
81
 
124
82
  if (ENABLE) {
125
83
  const BoundingRects = new WeakMap<Element, DOMRectReadOnly>()
126
-
127
- // optimization: persistent IO for rect fetching, reused across cycles
128
84
  let rectFetchObserver: IntersectionObserver | null = null
129
85
  let rectFetchResolve: ((value: boolean) => void) | null = null
130
86
  let rectFetchStartTime = 0
@@ -132,16 +88,12 @@ if (ENABLE) {
132
88
 
133
89
  function ensureRectFetchObserver() {
134
90
  if (rectFetchObserver) return rectFetchObserver
135
-
136
91
  rectFetchObserver = new IntersectionObserver(
137
92
  (entries) => {
138
93
  lastCallbackDelay = Math.round(performance.now() - rectFetchStartTime)
139
-
140
- // store all rects
141
94
  for (let i = 0; i < entries.length; i++) {
142
95
  BoundingRects.set(entries[i].target, entries[i].boundingClientRect)
143
96
  }
144
-
145
97
  if (
146
98
  process.env.NODE_ENV === 'development' &&
147
99
  isDebugLayout() &&
@@ -154,90 +106,64 @@ if (ENABLE) {
154
106
  'entries'
155
107
  )
156
108
  }
157
-
158
109
  if (rectFetchResolve) {
159
110
  rectFetchResolve(true)
160
111
  rectFetchResolve = null
161
112
  }
162
113
  },
163
- {
164
- threshold: 0,
165
- }
114
+ { threshold: 0 }
166
115
  )
167
-
168
116
  return rectFetchObserver
169
117
  }
170
118
 
171
- async function updateLayoutIfChanged(node: HTMLElement) {
119
+ function updateLayoutIfChanged(node: HTMLElement) {
172
120
  const onLayout = LayoutHandlers.get(node)
173
121
  if (typeof onLayout !== 'function') return
174
-
175
122
  const parentNode = node.parentElement
176
123
  if (!parentNode) return
177
124
 
178
125
  let nodeRect: DOMRectReadOnly | undefined
179
126
  let parentRect: DOMRectReadOnly | undefined
180
127
 
181
- // respect the strategy contract
182
128
  if (strategy === 'async') {
183
129
  nodeRect = BoundingRects.get(node)
184
130
  parentRect = BoundingRects.get(parentNode)
185
-
186
- if (!nodeRect || !parentRect) {
187
- return
188
- }
131
+ if (!nodeRect || !parentRect) return
189
132
  } else {
190
133
  nodeRect = node.getBoundingClientRect()
191
134
  parentRect = parentNode.getBoundingClientRect()
192
135
  }
193
-
194
136
  emitLayoutIfChanged(node, parentNode, nodeRect, parentRect)
195
137
  }
196
138
 
197
139
  const rAF =
198
140
  typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame : undefined
199
-
200
- // adaptive frame skipping with backoff
201
141
  const userSkipVal = process.env.TAMAGUI_LAYOUT_FRAME_SKIP
202
142
  const BASE_SKIP_FRAMES = userSkipVal ? +userSkipVal : 10
203
143
  const MAX_SKIP_FRAMES = 20
204
144
  let skipFrames = BASE_SKIP_FRAMES
205
145
  let frameCount = 0
206
-
207
- // stays true across the await below so a node registering mid-cycle cannot
208
- // start a second concurrent loop
209
146
  let frameScheduled = false
210
147
 
211
148
  function scheduleLayoutFrame() {
212
- if (frameScheduled || strategy === 'off' || Nodes.size === 0 || document.hidden) {
149
+ if (frameScheduled || strategy === 'off' || Nodes.size === 0 || document.hidden)
213
150
  return
214
- }
215
151
  frameScheduled = true
216
152
  rAF ? rAF(layoutOnAnimationFrame) : setTimeout(layoutOnAnimationFrame, 16)
217
153
  }
218
154
 
219
155
  async function layoutOnAnimationFrame() {
220
- // skip frames based on adaptive rate
221
156
  if (frameCount++ % skipFrames !== 0) {
222
157
  frameScheduled = false
223
158
  scheduleLayoutFrame()
224
159
  return
225
160
  }
226
-
227
- // reset frame count to avoid overflow
228
- if (frameCount >= Number.MAX_SAFE_INTEGER) {
229
- frameCount = 0
230
- }
161
+ if (frameCount >= Number.MAX_SAFE_INTEGER) frameCount = 0
231
162
 
232
163
  if (strategy !== 'off') {
233
164
  const activeNodes: HTMLElement[] = []
234
- // optimization: deduplicate parent observations
235
165
  const parentsToObserve = new Set<HTMLElement>()
236
166
 
237
- // collect non-disabled nodes and their unique parents. off-viewport
238
- // nodes stay in: a sheet or popper parks off-screen until its own
239
- // measurement arrives, so gating measurement on visibility deadlocks it
240
- // there, and RN fires onLayout for off-screen views anyway
241
167
  for (const node of Nodes) {
242
168
  const parentElement = node.parentElement
243
169
  if (!(parentElement instanceof HTMLElement)) {
@@ -253,45 +179,26 @@ if (ENABLE) {
253
179
  if (activeNodes.length > 0) {
254
180
  const io = ensureRectFetchObserver()
255
181
  rectFetchStartTime = performance.now()
182
+ for (let i = 0; i < activeNodes.length; i++) io.observe(activeNodes[i])
183
+ for (const parent of parentsToObserve) io.observe(parent)
256
184
 
257
- // observe all nodes
258
- for (let i = 0; i < activeNodes.length; i++) {
259
- io.observe(activeNodes[i])
260
- }
261
- // optimization: observe unique parents only (not N times for N children)
262
- for (const parent of parentsToObserve) {
263
- io.observe(parent)
264
- }
265
-
266
- // wait for callback
267
185
  await new Promise<boolean>((res) => {
268
186
  rectFetchResolve = res
269
187
  })
270
188
 
271
- // unobserve all to reset for next cycle
272
- for (let i = 0; i < activeNodes.length; i++) {
273
- io.unobserve(activeNodes[i])
274
- }
275
- for (const parent of parentsToObserve) {
276
- io.unobserve(parent)
277
- }
189
+ for (let i = 0; i < activeNodes.length; i++) io.unobserve(activeNodes[i])
190
+ for (const parent of parentsToObserve) io.unobserve(parent)
278
191
 
279
- // adaptive backoff: if IO was slow, skip more frames next cycle
280
192
  if (lastCallbackDelay > 50) {
281
193
  skipFrames = Math.min(skipFrames + 2, MAX_SKIP_FRAMES)
282
194
  } else if (lastCallbackDelay < 20) {
283
- // recover back to base rate when things are fast
284
195
  skipFrames = Math.max(skipFrames - 1, BASE_SKIP_FRAMES)
285
196
  }
286
197
 
287
- // process updates
288
- for (let i = 0; i < activeNodes.length; i++) {
289
- updateLayoutIfChanged(activeNodes[i])
290
- }
198
+ for (let i = 0; i < activeNodes.length; i++) updateLayoutIfChanged(activeNodes[i])
291
199
  }
292
200
  }
293
201
 
294
- // schedule next frame
295
202
  frameScheduled = false
296
203
  scheduleLayoutFrame()
297
204
  }
@@ -309,48 +216,33 @@ export const getElementLayoutEvent = (
309
216
  nodeRect: DOMRectReadOnly,
310
217
  parentRect: DOMRectReadOnly,
311
218
  node?: HTMLElement
312
- ): LayoutEvent => {
313
- return {
314
- nativeEvent: {
315
- layout: getRelativeDimensions(nodeRect, parentRect, node),
316
- target: nodeRect,
317
- },
318
- timeStamp: Date.now(),
319
- }
320
- }
219
+ ): LayoutEvent => ({
220
+ nativeEvent: {
221
+ layout: getRelativeDimensions(nodeRect, parentRect, node),
222
+ target: nodeRect,
223
+ },
224
+ timeStamp: Date.now(),
225
+ })
321
226
 
322
- /**
323
- * get pre-transform dimensions for a node.
324
- * uses offsetWidth/offsetHeight which report CSS layout dimensions
325
- * unaffected by transforms - this matches React Native's onLayout behavior.
326
- *
327
- * see: https://github.com/tamagui/tamagui/pull/2329
328
- */
329
227
  const getPreTransformDimensions = (
330
228
  node: HTMLElement
331
- ): { width: number; height: number } => {
332
- return {
333
- width: node.offsetWidth,
334
- height: node.offsetHeight,
335
- }
336
- }
229
+ ): { width: number; height: number } => ({
230
+ width: node.offsetWidth,
231
+ height: node.offsetHeight,
232
+ })
337
233
 
338
234
  const getRelativeDimensions = (
339
235
  a: DOMRectReadOnly,
340
236
  b: DOMRectReadOnly,
341
237
  aNode?: HTMLElement
342
238
  ) => {
343
- const { left, top } = a
344
- const x = left - b.left
345
- const y = top - b.top
346
-
347
- // get pre-transform dimensions when flag is enabled and node is available
239
+ const left = a.left - b.left
240
+ const top = a.top - b.top
348
241
  const { width, height } =
349
242
  usePretransformDimensions() && aNode
350
243
  ? getPreTransformDimensions(aNode)
351
244
  : { width: a.width, height: a.height }
352
-
353
- return { x, y, width, height, pageX: a.left, pageY: a.top }
245
+ return { x: left, y: top, width, height, pageX: a.left, pageY: a.top }
354
246
  }
355
247
 
356
248
  function emitLayoutIfChanged(
@@ -364,7 +256,6 @@ function emitLayoutIfChanged(
364
256
 
365
257
  const cachedRect = NodeRectCache.get(node)
366
258
  const cachedParentRect = NodeRectCache.get(parentNode)
367
-
368
259
  const nodeChanged = !cachedRect || !rectsEqual(cachedRect, nodeRect)
369
260
  const parentChanged = !cachedParentRect || !rectsEqual(cachedParentRect, parentRect)
370
261
 
@@ -374,17 +265,6 @@ function emitLayoutIfChanged(
374
265
  NodeRectCache.set(parentNode, parentRect)
375
266
 
376
267
  const event = getElementLayoutEvent(nodeRect, parentRect, node)
377
-
378
- if (process.env.NODE_ENV === 'development' && isDebugLayout()) {
379
- console.log('[useElementLayout] change', {
380
- tag: node.tagName,
381
- id: node.id || undefined,
382
- className: (node.className || '').slice(0, 60) || undefined,
383
- layout: event.nativeEvent.layout,
384
- first: !cachedRect,
385
- })
386
- }
387
-
388
268
  if (avoidUpdates) {
389
269
  queuedUpdates.set(node, () => onLayout(event))
390
270
  } else {
@@ -394,15 +274,11 @@ function emitLayoutIfChanged(
394
274
 
395
275
  function observeLayoutNode(node: HTMLElement, disableKey?: string) {
396
276
  Nodes.add(node)
397
- if (disableKey) {
398
- LayoutDisableKey.set(node, disableKey)
399
- } else {
400
- LayoutDisableKey.delete(node)
401
- }
277
+ if (disableKey) LayoutDisableKey.set(node, disableKey)
278
+ else LayoutDisableKey.delete(node)
402
279
  resumeLayoutLoop?.()
403
280
  }
404
281
 
405
- // register an arbitrary DOM element into the measurement loop without React lifecycle
406
282
  export function registerLayoutNode(
407
283
  node: HTMLElement,
408
284
  onChange: () => void,
@@ -420,12 +296,6 @@ function cleanupNode(node: HTMLElement) {
420
296
  NodeRectCache.delete(node)
421
297
  }
422
298
 
423
- const PrevHostNode = new WeakMap<object, HTMLElement | undefined>()
424
-
425
- // spec: onLayout fires one synchronous initial event on mount and on host swap
426
- // (RN parity, and before-paint so consumers can position without flicker).
427
- // bypasses the avoidUpdates queue on purpose; seeds the rect cache so the
428
- // measurement loop doesn't re-emit an identical event a frame later.
429
299
  function emitLayoutSync(node: HTMLElement) {
430
300
  const onLayout = LayoutHandlers.get(node)
431
301
  if (typeof onLayout !== 'function') return
@@ -444,85 +314,51 @@ export function useElementLayout(
444
314
  onLayout?: ((e: LayoutEvent) => void) | null
445
315
  ): void {
446
316
  const disableKey = useContext(DisableLayoutContextKey)
447
-
448
- // keep handlers up to date so polling always calls the latest callback
449
317
  const node = ensureWebElement(ref.current?.host)
450
318
  if (node && onLayout) {
451
319
  LayoutHandlers.set(node, onLayout)
452
320
  LayoutDisableKey.set(node, disableKey)
453
321
  }
454
322
 
455
- // detect mounts + host swaps after commit and fire the immediate sync layout event
456
323
  useIsomorphicLayoutEffect(() => {
457
324
  if (!onLayout) return
458
325
  const nextNode = ensureWebElement(ref.current?.host)
459
326
  const prevNode = PrevHostNode.get(ref)
460
- if (nextNode === prevNode) return
461
-
462
- if (prevNode) cleanupNode(prevNode)
463
- PrevHostNode.set(ref, nextNode)
464
- if (!nextNode) return
465
-
466
- LayoutHandlers.set(nextNode, onLayout)
467
- observeLayoutNode(nextNode, disableKey)
468
- emitLayoutSync(nextNode)
469
- })
470
-
471
- useIsomorphicLayoutEffect(() => {
472
- if (!onLayout) return
473
- const node = ref.current?.host
474
- if (!node) return
475
-
476
- LayoutHandlers.set(node, onLayout)
477
- observeLayoutNode(node, disableKey)
478
-
479
- if (process.env.NODE_ENV === 'development' && isDebugLayout()) {
480
- console.log('[useElementLayout] register', {
481
- tag: node.tagName,
482
- id: node.id || undefined,
483
- className: (node.className || '').slice(0, 60) || undefined,
484
- totalNodes: Nodes.size,
485
- })
327
+ if (nextNode !== prevNode) {
328
+ if (prevNode) cleanupNode(prevNode)
329
+ PrevHostNode.set(ref, nextNode)
330
+ if (nextNode) {
331
+ LayoutHandlers.set(nextNode, onLayout)
332
+ observeLayoutNode(nextNode, disableKey)
333
+ emitLayoutSync(nextNode)
334
+ }
486
335
  }
487
-
488
336
  return () => {
489
- cleanupNode(node)
490
-
491
- // also clean up any node from a mid-lifecycle host swap
492
- const swappedNode = PrevHostNode.get(ref)
493
- if (swappedNode && swappedNode !== node) {
494
- cleanupNode(swappedNode)
495
- }
337
+ const activeNode = ensureWebElement(ref.current?.host)
338
+ if (activeNode) cleanupNode(activeNode)
339
+ const swapped = PrevHostNode.get(ref)
340
+ if (swapped && swapped !== activeNode) cleanupNode(swapped)
496
341
  PrevHostNode.delete(ref)
497
342
  }
498
343
  }, [ref, !!onLayout])
499
344
  }
500
345
 
501
346
  function ensureWebElement<X>(x: X): HTMLElement | undefined {
502
- if (typeof HTMLElement === 'undefined') {
503
- return undefined
504
- }
347
+ if (typeof HTMLElement === 'undefined') return undefined
505
348
  return x instanceof HTMLElement ? x : undefined
506
349
  }
507
350
 
508
351
  export const getBoundingClientRectAsync = (
509
352
  node: HTMLElement | null
510
- ): Promise<DOMRectReadOnly | false> => {
511
- return new Promise<DOMRectReadOnly | false>((res) => {
353
+ ): Promise<DOMRectReadOnly | false> =>
354
+ new Promise((res) => {
512
355
  if (!node || node.nodeType !== 1) return res(false)
513
-
514
- const io = new IntersectionObserver(
515
- (entries) => {
516
- io.disconnect()
517
- return res(entries[0].boundingClientRect)
518
- },
519
- {
520
- threshold: 0,
521
- }
522
- )
356
+ const io = new IntersectionObserver((entries) => {
357
+ io.disconnect()
358
+ res(entries[0].boundingClientRect)
359
+ })
523
360
  io.observe(node)
524
361
  })
525
- }
526
362
 
527
363
  export const measureNode = async (
528
364
  node: HTMLElement,
@@ -541,9 +377,13 @@ export const measureNode = async (
541
377
  return null
542
378
  }
543
379
 
544
- type MeasureInWindowCb = (x: number, y: number, width: number, height: number) => void
545
-
546
- type MeasureCb = (
380
+ export type MeasureInWindowCb = (
381
+ x: number,
382
+ y: number,
383
+ width: number,
384
+ height: number
385
+ ) => void
386
+ export type MeasureCb = (
547
387
  x: number,
548
388
  y: number,
549
389
  width: number,
@@ -551,45 +391,35 @@ type MeasureCb = (
551
391
  pageX: number,
552
392
  pageY: number
553
393
  ) => void
394
+ export type WindowLayout = { pageX: number; pageY: number; width: number; height: number }
554
395
 
555
396
  export const measure = async (
556
397
  node: HTMLElement,
557
398
  callback: MeasureCb
558
399
  ): Promise<LayoutValue | null> => {
559
- const out = await measureNode(
560
- node,
561
- node.parentNode instanceof HTMLElement ? node.parentNode : null
562
- )
563
- if (out) {
564
- callback?.(out.x, out.y, out.width, out.height, out.pageX, out.pageY)
565
- }
400
+ const out = await measureNode(node, node.parentElement)
401
+ if (out) callback?.(out.x, out.y, out.width, out.height, out.pageX, out.pageY)
566
402
  return out
567
403
  }
568
404
 
569
- export function createMeasure(
570
- node: HTMLElement
571
- ): (callback: MeasureCb) => Promise<LayoutValue | null> {
572
- return (callback) => measure(node, callback)
573
- }
574
-
575
- type WindowLayout = { pageX: number; pageY: number; width: number; height: number }
405
+ export const createMeasure =
406
+ (node: HTMLElement): ((callback: MeasureCb) => Promise<LayoutValue | null>) =>
407
+ (callback: MeasureCb) =>
408
+ measure(node, callback)
576
409
 
577
410
  export const measureInWindow = async (
578
411
  node: HTMLElement,
579
412
  callback: MeasureInWindowCb
580
413
  ): Promise<WindowLayout | null> => {
581
414
  const out = await measureNode(node, null)
582
- if (out) {
583
- callback?.(out.pageX, out.pageY, out.width, out.height)
584
- }
415
+ if (out) callback?.(out.pageX, out.pageY, out.width, out.height)
585
416
  return out
586
417
  }
587
418
 
588
- export const createMeasureInWindow = (
589
- node: HTMLElement
590
- ): ((callback: MeasureInWindowCb) => Promise<WindowLayout | null>) => {
591
- return (callback) => measureInWindow(node, callback)
592
- }
419
+ export const createMeasureInWindow =
420
+ (node: HTMLElement): ((callback: MeasureInWindowCb) => Promise<WindowLayout | null>) =>
421
+ (callback: MeasureInWindowCb) =>
422
+ measureInWindow(node, callback)
593
423
 
594
424
  export const measureLayout = async (
595
425
  node: HTMLElement,
@@ -597,14 +427,13 @@ export const measureLayout = async (
597
427
  callback: MeasureCb
598
428
  ): Promise<LayoutValue | null> => {
599
429
  const out = await measureNode(node, relativeNode)
600
- if (out) {
601
- callback?.(out.x, out.y, out.width, out.height, out.pageX, out.pageY)
602
- }
430
+ if (out) callback?.(out.x, out.y, out.width, out.height, out.pageX, out.pageY)
603
431
  return out
604
432
  }
605
433
 
606
- export function createMeasureLayout(
607
- node: HTMLElement
608
- ): (relativeTo: HTMLElement, callback: MeasureCb) => Promise<LayoutValue | null> {
609
- return (relativeTo, callback) => measureLayout(node, relativeTo, callback)
610
- }
434
+ export const createMeasureLayout =
435
+ (
436
+ node: HTMLElement
437
+ ): ((relativeTo: HTMLElement, callback: MeasureCb) => Promise<LayoutValue | null>) =>
438
+ (relativeTo: HTMLElement, callback: MeasureCb) =>
439
+ measureLayout(node, relativeTo, callback)
package/types/index.d.ts CHANGED
@@ -6,8 +6,6 @@ export declare const LayoutMeasurementController: ({ disable, children }: {
6
6
  type TamaguiComponentStatePartial = {
7
7
  host?: any;
8
8
  };
9
- type LayoutMeasurementStrategy = "off" | "sync" | "async";
10
- export declare function setOnLayoutStrategy(state: LayoutMeasurementStrategy): void;
11
9
  export type LayoutValue = {
12
10
  x: number;
13
11
  y: number;
@@ -29,20 +27,20 @@ export declare function registerLayoutNode(node: HTMLElement, onChange: () => vo
29
27
  export declare function useElementLayout(ref: RefObject<TamaguiComponentStatePartial>, onLayout?: ((e: LayoutEvent) => void) | null): void;
30
28
  export declare const getBoundingClientRectAsync: (node: HTMLElement | null) => Promise<DOMRectReadOnly | false>;
31
29
  export declare const measureNode: (node: HTMLElement, relativeTo?: HTMLElement | null) => Promise<null | LayoutValue>;
32
- type MeasureInWindowCb = (x: number, y: number, width: number, height: number) => void;
33
- type MeasureCb = (x: number, y: number, width: number, height: number, pageX: number, pageY: number) => void;
34
- export declare const measure: (node: HTMLElement, callback: MeasureCb) => Promise<LayoutValue | null>;
35
- export declare function createMeasure(node: HTMLElement): (callback: MeasureCb) => Promise<LayoutValue | null>;
36
- type WindowLayout = {
30
+ export type MeasureInWindowCb = (x: number, y: number, width: number, height: number) => void;
31
+ export type MeasureCb = (x: number, y: number, width: number, height: number, pageX: number, pageY: number) => void;
32
+ export type WindowLayout = {
37
33
  pageX: number;
38
34
  pageY: number;
39
35
  width: number;
40
36
  height: number;
41
37
  };
38
+ export declare const measure: (node: HTMLElement, callback: MeasureCb) => Promise<LayoutValue | null>;
39
+ export declare const createMeasure: (node: HTMLElement) => ((callback: MeasureCb) => Promise<LayoutValue | null>);
42
40
  export declare const measureInWindow: (node: HTMLElement, callback: MeasureInWindowCb) => Promise<WindowLayout | null>;
43
41
  export declare const createMeasureInWindow: (node: HTMLElement) => ((callback: MeasureInWindowCb) => Promise<WindowLayout | null>);
44
42
  export declare const measureLayout: (node: HTMLElement, relativeNode: HTMLElement, callback: MeasureCb) => Promise<LayoutValue | null>;
45
- export declare function createMeasureLayout(node: HTMLElement): (relativeTo: HTMLElement, callback: MeasureCb) => Promise<LayoutValue | null>;
43
+ export declare const createMeasureLayout: (node: HTMLElement) => ((relativeTo: HTMLElement, callback: MeasureCb) => Promise<LayoutValue | null>);
46
44
  export {};
47
45
 
48
46
  //# sourceMappingURL=index.d.ts.map