@tamagui/core 1.126.13 → 1.126.14
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/hooks/useElementLayout.cjs +58 -64
- package/dist/cjs/hooks/useElementLayout.js +50 -63
- package/dist/cjs/hooks/useElementLayout.js.map +1 -1
- package/dist/cjs/hooks/useElementLayout.native.js +58 -95
- package/dist/cjs/hooks/useElementLayout.native.js.map +2 -2
- package/dist/cjs/index.cjs +4 -2
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/index.native.js +4 -2
- package/dist/cjs/index.native.js.map +2 -2
- package/dist/esm/hooks/useElementLayout.js +54 -64
- package/dist/esm/hooks/useElementLayout.js.map +1 -1
- package/dist/esm/hooks/useElementLayout.mjs +59 -65
- package/dist/esm/hooks/useElementLayout.mjs.map +1 -1
- package/dist/esm/hooks/useElementLayout.native.js +74 -107
- package/dist/esm/hooks/useElementLayout.native.js.map +1 -1
- package/dist/esm/index.js +5 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +2 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +2 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/native.js +102 -118
- package/dist/native.js.map +2 -2
- package/dist/test.native.js +99 -117
- package/dist/test.native.js.map +2 -2
- package/package.json +7 -7
- package/src/hooks/useElementLayout.tsx +97 -88
- package/src/index.tsx +6 -0
- package/types/hooks/useElementLayout.d.ts +2 -2
- package/types/hooks/useElementLayout.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/core",
|
|
3
|
-
"version": "1.126.
|
|
3
|
+
"version": "1.126.14",
|
|
4
4
|
"source": "src/index.tsx",
|
|
5
5
|
"main": "dist/cjs",
|
|
6
6
|
"module": "dist/esm",
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"native-test.d.ts"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@tamagui/react-native-media-driver": "1.126.
|
|
39
|
-
"@tamagui/react-native-use-pressable": "1.126.
|
|
40
|
-
"@tamagui/react-native-use-responder-events": "1.126.
|
|
41
|
-
"@tamagui/use-event": "1.126.
|
|
42
|
-
"@tamagui/web": "1.126.
|
|
38
|
+
"@tamagui/react-native-media-driver": "1.126.14",
|
|
39
|
+
"@tamagui/react-native-use-pressable": "1.126.14",
|
|
40
|
+
"@tamagui/react-native-use-responder-events": "1.126.14",
|
|
41
|
+
"@tamagui/use-event": "1.126.14",
|
|
42
|
+
"@tamagui/web": "1.126.14"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@tamagui/build": "1.126.
|
|
45
|
+
"@tamagui/build": "1.126.14",
|
|
46
46
|
"@testing-library/react": "^16.1.0",
|
|
47
47
|
"csstype": "^3.0.10",
|
|
48
48
|
"typescript": "^5.8.2",
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
2
|
-
import
|
|
1
|
+
import { isClient, useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
2
|
+
import {
|
|
3
|
+
isEqualShallow,
|
|
4
|
+
type TamaguiComponentStateRef,
|
|
5
|
+
___onDidFinishClientRender,
|
|
6
|
+
} from '@tamagui/web'
|
|
3
7
|
import type { RefObject } from 'react'
|
|
4
|
-
import { getBoundingClientRect } from '../helpers/getBoundingClientRect'
|
|
5
8
|
|
|
6
|
-
const LayoutHandlers = new WeakMap<
|
|
7
|
-
const
|
|
9
|
+
const LayoutHandlers = new WeakMap<HTMLElement, Function>()
|
|
10
|
+
const Nodes = new Set<HTMLElement>()
|
|
8
11
|
|
|
9
12
|
export type LayoutValue = {
|
|
10
13
|
x: number
|
|
@@ -23,48 +26,88 @@ export type LayoutEvent = {
|
|
|
23
26
|
timeStamp: number
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
const NodeRectCache = new WeakMap<HTMLElement, DOMRect>()
|
|
30
|
+
const ParentRectCache = new WeakMap<HTMLElement, DOMRect>()
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const rAF = typeof window !== 'undefined' ? window.requestAnimationFrame : undefined
|
|
33
|
+
|
|
34
|
+
if (isClient) {
|
|
35
|
+
if (rAF) {
|
|
36
|
+
// prevent thrashing during first hydration (somewhat, streaming gets trickier)
|
|
37
|
+
let avoidUpdates = true
|
|
38
|
+
const queuedUpdates = new Map<HTMLElement, Function>()
|
|
39
|
+
|
|
40
|
+
___onDidFinishClientRender(() => {
|
|
41
|
+
avoidUpdates = false
|
|
42
|
+
if (queuedUpdates) {
|
|
43
|
+
queuedUpdates.forEach((cb) => cb())
|
|
44
|
+
queuedUpdates.clear()
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
function updateLayoutIfChanged(node: HTMLElement) {
|
|
49
|
+
const nodeRect = node.getBoundingClientRect()
|
|
50
|
+
const parentNode = node.parentElement
|
|
51
|
+
const parentRect = parentNode?.getBoundingClientRect()
|
|
52
|
+
|
|
53
|
+
const onLayout = LayoutHandlers.get(node)
|
|
33
54
|
if (typeof onLayout !== 'function') return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
|
|
56
|
+
const cachedRect = NodeRectCache.get(node)
|
|
57
|
+
const cachedParentRect = parentNode ? NodeRectCache.get(parentNode) : null
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
!cachedRect ||
|
|
61
|
+
// has changed one rect
|
|
62
|
+
(!isEqualShallow(cachedRect, nodeRect) &&
|
|
63
|
+
(!cachedParentRect || !isEqualShallow(cachedParentRect, parentRect)))
|
|
64
|
+
) {
|
|
65
|
+
NodeRectCache.set(node, nodeRect)
|
|
66
|
+
if (parentRect && parentNode) {
|
|
67
|
+
ParentRectCache.set(parentNode, parentRect)
|
|
68
|
+
}
|
|
69
|
+
const event = getElementLayoutEvent(node)
|
|
70
|
+
if (avoidUpdates) {
|
|
71
|
+
queuedUpdates.set(node, () => onLayout(event))
|
|
72
|
+
} else {
|
|
73
|
+
onLayout(event)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
37
76
|
}
|
|
38
|
-
})
|
|
39
77
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
78
|
+
// note that getBoundingClientRect() does not thrash layout if its after an animation frame
|
|
79
|
+
rAF!(layoutOnAnimationFrame)
|
|
80
|
+
function layoutOnAnimationFrame() {
|
|
81
|
+
Nodes.forEach(updateLayoutIfChanged)
|
|
82
|
+
rAF!(layoutOnAnimationFrame)
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
if (process.env.NODE_ENV === 'development') {
|
|
86
|
+
console.warn(
|
|
87
|
+
`No requestAnimationFrame - please polyfill for onLayout to work correctly`
|
|
88
|
+
)
|
|
89
|
+
}
|
|
49
90
|
}
|
|
50
91
|
}
|
|
51
92
|
|
|
52
|
-
export const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
93
|
+
export const getElementLayoutEvent = (target: HTMLElement): LayoutEvent => {
|
|
94
|
+
let res: LayoutEvent | null = null
|
|
95
|
+
measureLayout(target, null, (x, y, width, height, left, top) => {
|
|
96
|
+
res = {
|
|
97
|
+
nativeEvent: {
|
|
98
|
+
layout: { x, y, width, height, left, top },
|
|
99
|
+
target,
|
|
100
|
+
},
|
|
101
|
+
timeStamp: Date.now(),
|
|
102
|
+
}
|
|
63
103
|
})
|
|
104
|
+
if (!res) {
|
|
105
|
+
throw new Error(`‼️`) // impossible
|
|
106
|
+
}
|
|
107
|
+
return res
|
|
64
108
|
}
|
|
65
109
|
|
|
66
|
-
|
|
67
|
-
|
|
110
|
+
// matching old RN callback API (can we remove?)
|
|
68
111
|
export const measureLayout = (
|
|
69
112
|
node: HTMLElement,
|
|
70
113
|
relativeTo: HTMLElement | null,
|
|
@@ -77,22 +120,17 @@ export const measureLayout = (
|
|
|
77
120
|
top: number
|
|
78
121
|
) => void
|
|
79
122
|
) => {
|
|
80
|
-
const relativeNode = relativeTo || node?.
|
|
123
|
+
const relativeNode = relativeTo || node?.parentElement
|
|
81
124
|
if (relativeNode instanceof HTMLElement) {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
relativeNodeDim
|
|
92
|
-
)
|
|
93
|
-
callback(x, y, width, height, left, top)
|
|
94
|
-
}
|
|
95
|
-
})
|
|
125
|
+
const nodeDim = node.getBoundingClientRect()
|
|
126
|
+
const relativeNodeDim = relativeNode.getBoundingClientRect()
|
|
127
|
+
if (relativeNodeDim && nodeDim) {
|
|
128
|
+
const { x, y, width, height, left, top } = getRelativeDimensions(
|
|
129
|
+
nodeDim,
|
|
130
|
+
relativeNodeDim
|
|
131
|
+
)
|
|
132
|
+
callback(x, y, width, height, left, top)
|
|
133
|
+
}
|
|
96
134
|
}
|
|
97
135
|
}
|
|
98
136
|
|
|
@@ -103,58 +141,29 @@ const getRelativeDimensions = (a: DOMRectReadOnly, b: DOMRectReadOnly) => {
|
|
|
103
141
|
return { x, y, width, height, left, top }
|
|
104
142
|
}
|
|
105
143
|
|
|
106
|
-
const getBoundingClientRectAsync = (
|
|
107
|
-
element: HTMLElement
|
|
108
|
-
): Promise<DOMRectReadOnly | undefined> => {
|
|
109
|
-
return new Promise((resolve) => {
|
|
110
|
-
function fallbackToSync() {
|
|
111
|
-
resolve(getBoundingClientRect(element))
|
|
112
|
-
}
|
|
113
|
-
const tm = setTimeout(fallbackToSync, 10)
|
|
114
|
-
const observer = new IntersectionObserver(
|
|
115
|
-
(entries, ob) => {
|
|
116
|
-
clearTimeout(tm)
|
|
117
|
-
ob.disconnect()
|
|
118
|
-
resolve(entries[0]?.boundingClientRect)
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
threshold: 0.0001,
|
|
122
|
-
}
|
|
123
|
-
)
|
|
124
|
-
observer.observe(element)
|
|
125
|
-
})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
144
|
export function useElementLayout(
|
|
129
145
|
ref: RefObject<TamaguiComponentStateRef>,
|
|
130
146
|
onLayout?: ((e: LayoutEvent) => void) | null
|
|
131
147
|
) {
|
|
132
|
-
const node = ref.current?.host as Element
|
|
133
|
-
|
|
134
148
|
// ensure always up to date so we can avoid re-running effect
|
|
149
|
+
const node = ref.current?.host as HTMLElement
|
|
135
150
|
if (node && onLayout) {
|
|
136
151
|
LayoutHandlers.set(node, onLayout)
|
|
137
152
|
}
|
|
138
153
|
|
|
139
154
|
useIsomorphicLayoutEffect(() => {
|
|
140
|
-
if (!
|
|
141
|
-
const node = ref.current?.host as
|
|
155
|
+
if (!onLayout) return
|
|
156
|
+
const node = ref.current?.host as HTMLElement
|
|
142
157
|
if (!node) return
|
|
143
158
|
|
|
144
|
-
// setup once
|
|
145
159
|
LayoutHandlers.set(node, onLayout)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
measureElement(node as HTMLElement).then(onLayout)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
resizeListeners.add(onResize)
|
|
152
|
-
resizeObserver.observe(node)
|
|
160
|
+
Nodes.add(node)
|
|
161
|
+
onLayout(getElementLayoutEvent(node))
|
|
153
162
|
|
|
154
163
|
return () => {
|
|
164
|
+
Nodes.delete(node)
|
|
155
165
|
LayoutHandlers.delete(node)
|
|
156
|
-
|
|
157
|
-
resizeObserver?.unobserve(node)
|
|
166
|
+
NodeRectCache.delete(node)
|
|
158
167
|
}
|
|
159
168
|
}, [ref, !!onLayout])
|
|
160
169
|
}
|
package/src/index.tsx
CHANGED
|
@@ -29,6 +29,12 @@ import type { RNTextProps, RNViewProps } from './reactNativeTypes'
|
|
|
29
29
|
import { usePressability } from './vendor/Pressability'
|
|
30
30
|
import { addNativeValidStyles } from './addNativeValidStyles'
|
|
31
31
|
|
|
32
|
+
// helpful for usage outside of tamagui
|
|
33
|
+
export {
|
|
34
|
+
getElementLayoutEvent,
|
|
35
|
+
type LayoutEvent,
|
|
36
|
+
} from './hooks/useElementLayout'
|
|
37
|
+
|
|
32
38
|
// add newer style props based on react native version
|
|
33
39
|
addNativeValidStyles()
|
|
34
40
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TamaguiComponentStateRef } from '@tamagui/web';
|
|
2
2
|
import type { RefObject } from 'react';
|
|
3
3
|
export type LayoutValue = {
|
|
4
4
|
x: number;
|
|
@@ -15,7 +15,7 @@ export type LayoutEvent = {
|
|
|
15
15
|
};
|
|
16
16
|
timeStamp: number;
|
|
17
17
|
};
|
|
18
|
-
export declare const
|
|
18
|
+
export declare const getElementLayoutEvent: (target: HTMLElement) => LayoutEvent;
|
|
19
19
|
export declare const measureLayout: (node: HTMLElement, relativeTo: HTMLElement | null, callback: (x: number, y: number, width: number, height: number, left: number, top: number) => void) => void;
|
|
20
20
|
export declare function useElementLayout(ref: RefObject<TamaguiComponentStateRef>, onLayout?: ((e: LayoutEvent) => void) | null): void;
|
|
21
21
|
//# sourceMappingURL=useElementLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useElementLayout.d.ts","sourceRoot":"","sources":["../../src/hooks/useElementLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"useElementLayout.d.ts","sourceRoot":"","sources":["../../src/hooks/useElementLayout.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE;QACX,MAAM,EAAE,WAAW,CAAA;QACnB,MAAM,EAAE,GAAG,CAAA;KACZ,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAkED,eAAO,MAAM,qBAAqB,GAAI,QAAQ,WAAW,KAAG,WAe3D,CAAA;AAGD,eAAO,MAAM,aAAa,GACxB,MAAM,WAAW,EACjB,YAAY,WAAW,GAAG,IAAI,EAC9B,UAAU,CACR,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,KACR,IAAI,SAcV,CAAA;AASD,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,SAAS,CAAC,wBAAwB,CAAC,EACxC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,IAAI,QAuB7C"}
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { StackNonStyleProps, StackStyleBase, TamaDefer, TamaguiComponent, TamaguiElement, TamaguiTextElement, TextNonStyleProps, TextProps, TextStylePropsBase } from '@tamagui/web';
|
|
2
2
|
import { createTamagui as createTamaguiWeb } from '@tamagui/web';
|
|
3
3
|
import type { RNTextProps, RNViewProps } from './reactNativeTypes';
|
|
4
|
+
export { getElementLayoutEvent, type LayoutEvent, } from './hooks/useElementLayout';
|
|
4
5
|
type RNExclusiveViewProps = Omit<RNViewProps, keyof StackNonStyleProps>;
|
|
5
6
|
export interface RNTamaguiViewNonStyleProps extends StackNonStyleProps, RNExclusiveViewProps {
|
|
6
7
|
}
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,kBAAkB,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EAKL,aAAa,IAAI,gBAAgB,EAElC,MAAM,cAAc,CAAA;AAOrB,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,kBAAkB,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EAKL,aAAa,IAAI,gBAAgB,EAElC,MAAM,cAAc,CAAA;AAOrB,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAKlE,OAAO,EACL,qBAAqB,EACrB,KAAK,WAAW,GACjB,MAAM,0BAA0B,CAAA;AAOjC,KAAK,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,kBAAkB,CAAC,CAAA;AACvE,MAAM,WAAW,0BACf,SAAQ,kBAAkB,EACxB,oBAAoB;CAAG;AAE3B,KAAK,aAAa,GAAG,gBAAgB,CACnC,SAAS,EACT,cAAc,EACd,0BAA0B,EAC1B,cAAc,EACd,EAAE,CACH,CAAA;AAED,KAAK,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,SAAS,CAAC,CAAA;AAC9D,MAAM,WAAW,0BACf,SAAQ,iBAAiB,EACvB,oBAAoB;CAAG;AAE3B,KAAK,aAAa,GAAG,gBAAgB,CACnC,SAAS,EACT,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,EAAE,CACH,CAAA;AAGD,cAAc,cAAc,CAAA;AAG5B,cAAc,oBAAoB,CAAA;AAGlC,eAAO,MAAM,aAAa,EAAE,OAAO,gBAOlC,CAAA;AAmLD,eAAO,MAAM,IAAI,EAAqB,aAAa,CAAA;AACnD,eAAO,MAAM,KAAK,EAAsB,aAAa,CAAA;AACrD,eAAO,MAAM,IAAI,EAAqB,aAAa,CAAA"}
|