@tamagui/native 3.0.0-beta.924.1 → 3.0.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.
Files changed (133) hide show
  1. package/dist/cjs/PressBoundary.cjs +2 -48
  2. package/dist/cjs/PressBoundary.native.cjs +3 -3
  3. package/dist/cjs/PressBoundary.native.js +3 -3
  4. package/dist/cjs/PressBoundary.native.js.map +1 -1
  5. package/dist/cjs/components.cjs +6 -2
  6. package/dist/cjs/components.native.cjs +6 -2
  7. package/dist/cjs/components.native.js +6 -2
  8. package/dist/cjs/components.native.js.map +1 -1
  9. package/dist/cjs/expoUIMenuAdapter.native.cjs +1 -5
  10. package/dist/cjs/expoUIMenuAdapter.native.js +1 -5
  11. package/dist/cjs/expoUIMenuAdapter.native.js.map +1 -1
  12. package/dist/cjs/expoUIMenuView.cjs +82 -0
  13. package/dist/cjs/expoUIMenuView.native.cjs +100 -0
  14. package/dist/cjs/expoUIMenuView.native.js +102 -0
  15. package/dist/cjs/expoUIMenuView.native.js.map +1 -0
  16. package/dist/cjs/index.cjs +0 -2
  17. package/dist/cjs/index.native.cjs +0 -2
  18. package/dist/cjs/index.native.js +0 -2
  19. package/dist/cjs/index.native.js.map +1 -1
  20. package/dist/cjs/nativeMenuContext.cjs +3 -1
  21. package/dist/cjs/nativeMenuContext.native.cjs +6 -1
  22. package/dist/cjs/nativeMenuContext.native.js +6 -1
  23. package/dist/cjs/nativeMenuContext.native.js.map +1 -1
  24. package/dist/cjs/setup-expo-ui-menu.cjs +6 -1
  25. package/dist/cjs/setup-expo-ui-menu.native.cjs +6 -1
  26. package/dist/cjs/setup-expo-ui-menu.native.js +6 -1
  27. package/dist/cjs/setup-expo-ui-menu.native.js.map +1 -1
  28. package/dist/cjs/setup-one-portal.cjs +23 -0
  29. package/dist/cjs/setup-one-portal.native.cjs +25 -0
  30. package/dist/cjs/setup-one-portal.native.js +27 -0
  31. package/dist/cjs/setup-one-portal.native.js.map +1 -0
  32. package/dist/esm/PressBoundary.mjs +3 -43
  33. package/dist/esm/PressBoundary.mjs.map +1 -1
  34. package/dist/esm/PressBoundary.native.js.map +1 -1
  35. package/dist/esm/components.mjs +6 -2
  36. package/dist/esm/components.mjs.map +1 -1
  37. package/dist/esm/components.native.js +6 -2
  38. package/dist/esm/components.native.js.map +1 -1
  39. package/dist/esm/expoUIMenuAdapter.native.js +1 -5
  40. package/dist/esm/expoUIMenuAdapter.native.js.map +1 -1
  41. package/dist/esm/expoUIMenuView.mjs +63 -0
  42. package/dist/esm/expoUIMenuView.mjs.map +1 -0
  43. package/dist/esm/expoUIMenuView.native.js +73 -0
  44. package/dist/esm/expoUIMenuView.native.js.map +1 -0
  45. package/dist/esm/index.js +1 -2
  46. package/dist/esm/index.mjs +1 -2
  47. package/dist/esm/index.native.js +1 -2
  48. package/dist/esm/nativeMenuContext.mjs +3 -1
  49. package/dist/esm/nativeMenuContext.mjs.map +1 -1
  50. package/dist/esm/nativeMenuContext.native.js +6 -1
  51. package/dist/esm/nativeMenuContext.native.js.map +1 -1
  52. package/dist/esm/setup-burnt.mjs +1 -6
  53. package/dist/esm/setup-burnt.native.js +0 -5
  54. package/dist/esm/setup-expo-ui-menu.mjs +6 -6
  55. package/dist/esm/setup-expo-ui-menu.mjs.map +1 -1
  56. package/dist/esm/setup-expo-ui-menu.native.js +6 -6
  57. package/dist/esm/setup-expo-ui-menu.native.js.map +1 -1
  58. package/dist/esm/setup-gesture-handler.mjs +1 -6
  59. package/dist/esm/setup-gesture-handler.native.js +0 -5
  60. package/dist/esm/setup-keyboard-controller.native.js +0 -5
  61. package/dist/esm/setup-one-portal.mjs +26 -0
  62. package/dist/esm/setup-one-portal.mjs.map +1 -0
  63. package/dist/esm/setup-one-portal.native.js +26 -0
  64. package/dist/esm/setup-one-portal.native.js.map +1 -0
  65. package/dist/esm/setup-teleport.mjs +1 -6
  66. package/dist/esm/setup-teleport.native.js +0 -5
  67. package/dist/esm/setup-worklets.mjs +1 -6
  68. package/dist/esm/setup-worklets.native.js +0 -5
  69. package/dist/esm/setup-zeego.mjs +2 -7
  70. package/dist/esm/setup-zeego.native.js +0 -5
  71. package/package.json +28 -26
  72. package/setup-one-portal/index.cjs +2 -0
  73. package/setup-one-portal/index.js +2 -0
  74. package/setup-one-portal/index.native.cjs +2 -0
  75. package/setup-one-portal/index.native.js +2 -0
  76. package/setup-one-portal.cjs +1 -0
  77. package/src/PressBoundary.native.tsx +75 -0
  78. package/src/PressBoundary.tsx +16 -83
  79. package/src/components.tsx +3 -2
  80. package/src/expoUIMenuAdapter.tsx +2 -2
  81. package/src/expoUIMenuView.tsx +124 -0
  82. package/src/gesture-handler.ts +1 -1
  83. package/src/index.ts +0 -7
  84. package/src/nativeMenuContext.ts +7 -1
  85. package/src/setup-expo-ui-menu.ts +9 -1
  86. package/src/setup-one-portal.ts +32 -0
  87. package/src/types.ts +11 -5
  88. package/types/PressBoundary.d.ts +13 -14
  89. package/types/PressBoundary.d.ts.map +2 -2
  90. package/types/PressBoundary.native.d.ts +8 -0
  91. package/types/PressBoundary.native.d.ts.map +11 -0
  92. package/types/components.d.ts.map +1 -1
  93. package/types/expoUIMenuAdapter.d.ts +27 -1
  94. package/types/expoUIMenuAdapter.d.ts.map +2 -2
  95. package/types/expoUIMenuView.d.ts +24 -0
  96. package/types/expoUIMenuView.d.ts.map +11 -0
  97. package/types/gesture-handler.d.ts +1 -1
  98. package/types/gesture-handler.d.ts.map +1 -1
  99. package/types/index.d.ts +1 -5
  100. package/types/index.d.ts.map +2 -2
  101. package/types/nativeMenuContext.d.ts.map +2 -2
  102. package/types/setup-expo-ui-menu.d.ts.map +1 -1
  103. package/types/setup-one-portal.d.ts +3 -0
  104. package/types/setup-one-portal.d.ts.map +11 -0
  105. package/types/types.d.ts +10 -4
  106. package/types/types.d.ts.map +2 -2
  107. package/dist/cjs/linearGradientState.cjs +0 -41
  108. package/dist/cjs/linearGradientState.native.cjs +0 -43
  109. package/dist/cjs/linearGradientState.native.js +0 -45
  110. package/dist/cjs/linearGradientState.native.js.map +0 -1
  111. package/dist/cjs/setup-expo-linear-gradient.cjs +0 -16
  112. package/dist/cjs/setup-expo-linear-gradient.native.cjs +0 -18
  113. package/dist/cjs/setup-expo-linear-gradient.native.js +0 -20
  114. package/dist/cjs/setup-expo-linear-gradient.native.js.map +0 -1
  115. package/dist/esm/linearGradientState.mjs +0 -22
  116. package/dist/esm/linearGradientState.mjs.map +0 -1
  117. package/dist/esm/linearGradientState.native.js +0 -22
  118. package/dist/esm/linearGradientState.native.js.map +0 -1
  119. package/dist/esm/setup-expo-linear-gradient.mjs +0 -24
  120. package/dist/esm/setup-expo-linear-gradient.mjs.map +0 -1
  121. package/dist/esm/setup-expo-linear-gradient.native.js +0 -24
  122. package/dist/esm/setup-expo-linear-gradient.native.js.map +0 -1
  123. package/setup-expo-linear-gradient/index.cjs +0 -2
  124. package/setup-expo-linear-gradient/index.js +0 -2
  125. package/setup-expo-linear-gradient/index.native.cjs +0 -2
  126. package/setup-expo-linear-gradient/index.native.js +0 -2
  127. package/setup-expo-linear-gradient.cjs +0 -1
  128. package/src/linearGradientState.ts +0 -27
  129. package/src/setup-expo-linear-gradient.ts +0 -36
  130. package/types/linearGradientState.d.ts +0 -9
  131. package/types/linearGradientState.d.ts.map +0 -11
  132. package/types/setup-expo-linear-gradient.d.ts +0 -3
  133. package/types/setup-expo-linear-gradient.d.ts.map +0 -11
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@tamagui/native",
3
- "version": "3.0.0-beta.924.1",
3
+ "version": "3.0.1",
4
+ "license": "MIT",
4
5
  "description": "Native setup modules for Tamagui - portals, gesture handler, worklets, and more",
5
6
  "type": "module",
6
7
  "sideEffects": [
@@ -15,8 +16,6 @@
15
16
  "gesture-handler.cjs",
16
17
  "setup-burnt",
17
18
  "setup-burnt.cjs",
18
- "setup-expo-linear-gradient",
19
- "setup-expo-linear-gradient.cjs",
20
19
  "setup-expo-ui-menu",
21
20
  "setup-expo-ui-menu.cjs",
22
21
  "setup-gesture-handler",
@@ -25,6 +24,8 @@
25
24
  "setup-keyboard-controller.cjs",
26
25
  "setup-safe-area",
27
26
  "setup-safe-area.cjs",
27
+ "setup-one-portal",
28
+ "setup-one-portal.cjs",
28
29
  "setup-teleport",
29
30
  "setup-teleport.cjs",
30
31
  "setup-worklets",
@@ -37,6 +38,9 @@
37
38
  "types": "./types/index.d.ts",
38
39
  "typesVersions": {
39
40
  "*": {
41
+ "setup-one-portal": [
42
+ "./types/setup-one-portal.d.ts"
43
+ ],
40
44
  "setup-teleport": [
41
45
  "./types/setup-teleport.d.ts"
42
46
  ],
@@ -52,9 +56,6 @@
52
56
  "setup-safe-area": [
53
57
  "./types/setup-safe-area.d.ts"
54
58
  ],
55
- "setup-expo-linear-gradient": [
56
- "./types/setup-expo-linear-gradient.d.ts"
57
- ],
58
59
  "setup-keyboard-controller": [
59
60
  "./types/setup-keyboard-controller.d.ts"
60
61
  ],
@@ -80,6 +81,15 @@
80
81
  "require": "./dist/cjs/index.cjs",
81
82
  "default": "./dist/esm/index.mjs"
82
83
  },
84
+ "./setup-one-portal": {
85
+ "types": "./types/setup-one-portal.d.ts",
86
+ "react-native": "./dist/esm/setup-one-portal.native.js",
87
+ "browser": "./dist/esm/setup-one-portal.mjs",
88
+ "module": "./dist/esm/setup-one-portal.mjs",
89
+ "import": "./dist/esm/setup-one-portal.mjs",
90
+ "require": "./dist/cjs/setup-one-portal.cjs",
91
+ "default": "./dist/esm/setup-one-portal.mjs"
92
+ },
83
93
  "./setup-teleport": {
84
94
  "types": "./types/setup-teleport.d.ts",
85
95
  "react-native": "./dist/esm/setup-teleport.native.js",
@@ -125,15 +135,6 @@
125
135
  "require": "./dist/cjs/setup-safe-area.cjs",
126
136
  "default": "./dist/esm/setup-safe-area.mjs"
127
137
  },
128
- "./setup-expo-linear-gradient": {
129
- "types": "./types/setup-expo-linear-gradient.d.ts",
130
- "react-native": "./dist/esm/setup-expo-linear-gradient.native.js",
131
- "browser": "./dist/esm/setup-expo-linear-gradient.mjs",
132
- "module": "./dist/esm/setup-expo-linear-gradient.mjs",
133
- "import": "./dist/esm/setup-expo-linear-gradient.mjs",
134
- "require": "./dist/cjs/setup-expo-linear-gradient.cjs",
135
- "default": "./dist/esm/setup-expo-linear-gradient.mjs"
136
- },
137
138
  "./setup-keyboard-controller": {
138
139
  "types": "./types/setup-keyboard-controller.d.ts",
139
140
  "react-native": "./dist/esm/setup-keyboard-controller.native.js",
@@ -181,18 +182,18 @@
181
182
  "clean:build": "tamagui-build clean:build"
182
183
  },
183
184
  "dependencies": {
184
- "@tamagui/compose-refs": "3.0.0-beta.924.1"
185
+ "@tamagui/compose-refs": "3.0.1",
186
+ "@tamagui/react-native-types": "3.0.1"
185
187
  },
186
188
  "devDependencies": {
187
189
  "@expo/ui": "~57.0.12",
188
- "@tamagui/build": "3.0.0-beta.924.1",
190
+ "@tamagui/build": "3.0.1",
189
191
  "burnt": "^0.13.0",
190
- "expo-linear-gradient": "~57.0.1",
191
192
  "react": "19.2.3",
192
- "react-native": "0.86.2",
193
- "react-native-gesture-handler": "~2.32.0",
193
+ "react-native": "0.87.1",
194
+ "react-native-gesture-handler": "3.3.0",
194
195
  "react-native-keyboard-controller": "1.21.11",
195
- "react-native-safe-area-context": "~5.7.0",
196
+ "react-native-safe-area-context": "5.10.1",
196
197
  "react-native-teleport": "^1.0.0",
197
198
  "react-native-web": "~0.21.0",
198
199
  "react-native-worklets-core": "^1.0.0",
@@ -201,7 +202,7 @@
201
202
  "peerDependencies": {
202
203
  "@expo/ui": "*",
203
204
  "burnt": "*",
204
- "expo-linear-gradient": "*",
205
+ "one": "*",
205
206
  "react": "*",
206
207
  "react-native": "*",
207
208
  "react-native-gesture-handler": "*",
@@ -225,9 +226,6 @@
225
226
  "react-native-web": {
226
227
  "optional": true
227
228
  },
228
- "expo-linear-gradient": {
229
- "optional": true
230
- },
231
229
  "react-native-gesture-handler": {
232
230
  "optional": true
233
231
  },
@@ -245,11 +243,15 @@
245
243
  },
246
244
  "zeego": {
247
245
  "optional": true
246
+ },
247
+ "one": {
248
+ "optional": true
248
249
  }
249
250
  },
250
251
  "repository": {
251
252
  "type": "git",
252
253
  "url": "git+https://github.com/tamagui/tamagui.git",
253
254
  "directory": "code/core/native"
254
- }
255
+ },
256
+ "releaseSourceCommit": "c156b7cc55e5a6cc5883ebc8189720850ac32dbd"
255
257
  }
@@ -0,0 +1,2 @@
1
+ // compat with tamagui static compiler
2
+ Object.assign(module.exports, require('../dist/cjs/setup-one-portal.cjs'))
@@ -0,0 +1,2 @@
1
+ // compat with metro without package exports
2
+ Object.assign(module.exports, require('../dist/cjs/setup-one-portal.cjs'))
@@ -0,0 +1,2 @@
1
+ // compat with tamagui static compiler
2
+ Object.assign(module.exports, require('../dist/cjs/setup-one-portal.native.js'))
@@ -0,0 +1,2 @@
1
+ // compat with metro without package exports
2
+ Object.assign(module.exports, require('../dist/cjs/setup-one-portal.native.js'))
@@ -0,0 +1 @@
1
+ Object.assign(module.exports, require('./dist/cjs/setup-one-portal.cjs'))
@@ -0,0 +1,75 @@
1
+ import { createRefComponent } from '@tamagui/compose-refs'
2
+ import React from 'react'
3
+ import { View, type ViewInstance } from 'react-native'
4
+ import {
5
+ claimExternalPressOwnership,
6
+ releaseExternalPressOwnership,
7
+ type ExternalPressOwnershipToken,
8
+ } from './gestureState'
9
+ import type { PressBoundaryProps } from './types'
10
+
11
+ function composeFirst<T extends (...args: any[]) => void>(ours: T, theirs?: T) {
12
+ return (...args: Parameters<T>) => {
13
+ ours(...args)
14
+ theirs?.(...args)
15
+ }
16
+ }
17
+
18
+ function composeLast<T extends (...args: any[]) => void>(theirs: T | undefined, ours: T) {
19
+ return (...args: Parameters<T>) => {
20
+ theirs?.(...args)
21
+ ours(...args)
22
+ }
23
+ }
24
+
25
+ export const PressBoundary: (
26
+ props: PressBoundaryProps & { ref?: React.Ref<ViewInstance> }
27
+ ) => React.ReactNode = createRefComponent<ViewInstance, PressBoundaryProps>(
28
+ function PressBoundary(
29
+ {
30
+ enabled,
31
+ stopPropagation,
32
+ debugName,
33
+ onTouchStart,
34
+ onTouchEnd,
35
+ onTouchCancel,
36
+ onResponderGrant,
37
+ onResponderRelease,
38
+ onResponderTerminate,
39
+ ...props
40
+ },
41
+ forwardedRef
42
+ ) {
43
+ const tokenRef = React.useRef<ExternalPressOwnershipToken | null>(null)
44
+ const isEnabled = enabled ?? stopPropagation ?? true
45
+
46
+ const claim = React.useCallback((): void => {
47
+ if (!isEnabled) return
48
+ if (tokenRef.current) {
49
+ releaseExternalPressOwnership(tokenRef.current, debugName)
50
+ }
51
+ tokenRef.current = claimExternalPressOwnership(debugName)
52
+ }, [debugName, isEnabled])
53
+
54
+ const release = React.useCallback((): void => {
55
+ if (!tokenRef.current) return
56
+ releaseExternalPressOwnership(tokenRef.current, debugName)
57
+ tokenRef.current = null
58
+ }, [debugName])
59
+
60
+ React.useEffect(() => release, [release])
61
+
62
+ return (
63
+ <View
64
+ ref={forwardedRef}
65
+ {...props}
66
+ onTouchStart={composeFirst(claim, onTouchStart)}
67
+ onTouchEnd={composeLast(onTouchEnd, release)}
68
+ onTouchCancel={composeLast(onTouchCancel, release)}
69
+ onResponderGrant={composeFirst(claim, onResponderGrant)}
70
+ onResponderRelease={composeLast(onResponderRelease, release)}
71
+ onResponderTerminate={composeLast(onResponderTerminate, release)}
72
+ />
73
+ )
74
+ }
75
+ )
@@ -1,84 +1,17 @@
1
- import { createRefComponent } from '@tamagui/compose-refs'
2
- import React from 'react'
3
- import { View, type ViewProps } from 'react-native'
4
- import {
5
- claimExternalPressOwnership,
6
- releaseExternalPressOwnership,
7
- type ExternalPressOwnershipToken,
8
- } from './gestureState'
9
-
10
- export interface PressBoundaryProps extends ViewProps {
11
- enabled?: boolean
12
- /**
13
- * Alias for enabling the boundary. The behavior is limited to Tamagui's
14
- * shared press ownership and does not patch arbitrary RN bubbling.
15
- */
16
- stopPropagation?: boolean
17
- debugName?: string | null
18
- }
19
-
20
- function composeFirst<T extends (...args: any[]) => void>(ours: T, theirs?: T) {
21
- return (...args: Parameters<T>) => {
22
- ours(...args)
23
- theirs?.(...args)
24
- }
25
- }
26
-
27
- function composeLast<T extends (...args: any[]) => void>(theirs: T | undefined, ours: T) {
28
- return (...args: Parameters<T>) => {
29
- theirs?.(...args)
30
- ours(...args)
31
- }
1
+ import type { ReactNode, Ref } from 'react'
2
+
3
+ import type { PressBoundaryProps } from './types'
4
+
5
+ /**
6
+ * Renders children as-is.
7
+ *
8
+ * The boundary exists to arbitrate Tamagui's shared press ownership with
9
+ * react-native-gesture-handler, which only runs on native, so on web there is
10
+ * nothing to claim and no view worth adding. `ref` is accepted and ignored for
11
+ * the same reason: there is no host node here to hand back.
12
+ */
13
+ export function PressBoundary({
14
+ children,
15
+ }: PressBoundaryProps & { ref?: Ref<unknown> }): ReactNode {
16
+ return <>{children}</>
32
17
  }
33
-
34
- export const PressBoundary: (
35
- props: PressBoundaryProps & { ref?: React.Ref<View> }
36
- ) => React.ReactNode = createRefComponent<View, PressBoundaryProps>(
37
- function PressBoundary(
38
- {
39
- enabled,
40
- stopPropagation,
41
- debugName,
42
- onTouchStart,
43
- onTouchEnd,
44
- onTouchCancel,
45
- onResponderGrant,
46
- onResponderRelease,
47
- onResponderTerminate,
48
- ...props
49
- },
50
- forwardedRef
51
- ) {
52
- const tokenRef = React.useRef<ExternalPressOwnershipToken | null>(null)
53
- const isEnabled = enabled ?? stopPropagation ?? true
54
-
55
- const claim = React.useCallback((): void => {
56
- if (!isEnabled) return
57
- if (tokenRef.current) {
58
- releaseExternalPressOwnership(tokenRef.current, debugName)
59
- }
60
- tokenRef.current = claimExternalPressOwnership(debugName)
61
- }, [debugName, isEnabled])
62
-
63
- const release = React.useCallback((): void => {
64
- if (!tokenRef.current) return
65
- releaseExternalPressOwnership(tokenRef.current, debugName)
66
- tokenRef.current = null
67
- }, [debugName])
68
-
69
- React.useEffect(() => release, [release])
70
-
71
- return (
72
- <View
73
- ref={forwardedRef}
74
- {...props}
75
- onTouchStart={composeFirst(claim, onTouchStart)}
76
- onTouchEnd={composeLast(onTouchEnd, release)}
77
- onTouchCancel={composeLast(onTouchCancel, release)}
78
- onResponderGrant={composeFirst(claim, onResponderGrant)}
79
- onResponderRelease={composeLast(onResponderRelease, release)}
80
- onResponderTerminate={composeLast(onResponderTerminate, release)}
81
- />
82
- )
83
- }
84
- )
@@ -31,8 +31,8 @@ export function NativePortalHost({ name }: NativePortalHostProps): ReactNode {
31
31
  const state = getPortal().state
32
32
  if (state.type !== 'teleport') return null
33
33
 
34
- const { PortalHost } = (globalThis as any).__tamagui_teleport
35
- return <PortalHost name={name} />
34
+ const { PortalHost, hostStyle } = (globalThis as any).__tamagui_teleport
35
+ return <PortalHost name={name} style={hostStyle} />
36
36
  }
37
37
 
38
38
  /**
@@ -44,5 +44,6 @@ export function NativePortalProvider({ children }: NativePortalProviderProps): R
44
44
  if (state.type !== 'teleport') return <>{children}</>
45
45
 
46
46
  const { PortalProvider } = (globalThis as any).__tamagui_teleport
47
+ if (!PortalProvider) return <>{children}</>
47
48
  return <PortalProvider>{children}</PortalProvider>
48
49
  }
@@ -3,7 +3,7 @@ import React from 'react'
3
3
 
4
4
  import type { NativeMenuAdapter, NativeMenuModule } from './nativeMenuState'
5
5
 
6
- type ExpoMenuAction = {
6
+ export type ExpoMenuAction = {
7
7
  id: string
8
8
  title: string
9
9
  image?: unknown
@@ -17,7 +17,7 @@ type ExpoMenuAction = {
17
17
  displayInline?: boolean
18
18
  }
19
19
 
20
- type ExpoMenuViewProps = {
20
+ export type ExpoMenuViewProps = {
21
21
  actions: ExpoMenuAction[]
22
22
  title?: string
23
23
  shouldOpenOnLongPress?: boolean
@@ -0,0 +1,124 @@
1
+ import type { ComponentType, ReactNode } from 'react'
2
+ import React from 'react'
3
+
4
+ import type { ExpoMenuAction, ExpoMenuViewProps } from './expoUIMenuAdapter'
5
+
6
+ // the swiftui menu behind every native Menu and ContextMenu trigger on ios,
7
+ // composed from @expo/ui/swift-ui the same way @expo/ui's community MenuView
8
+ // is, minus `matchContents` on the Host. that flag copies each SwiftUI
9
+ // measurement back onto the host's yoga node as a fixed height, and yoga then
10
+ // measures the trigger's react-native children against that height, so trigger
11
+ // content can shrink but never grow: a row that mounts empty and fills in later
12
+ // stays at 0pt, and a streaming paragraph stays at its first line count. without
13
+ // the flag the host takes its height from the hosted react-native subtree like
14
+ // any other view, and RNHostView still sizes the SwiftUI side from that
15
+ // subtree's yoga bounds.
16
+
17
+ type SwiftUIModule = {
18
+ Button: ComponentType<any>
19
+ ContextMenu: ComponentType<any> & {
20
+ Trigger: ComponentType<any>
21
+ Items: ComponentType<any>
22
+ }
23
+ Host: ComponentType<any>
24
+ Menu: ComponentType<any>
25
+ RNHostView: ComponentType<any>
26
+ Section: ComponentType<any>
27
+ Toggle: ComponentType<any>
28
+ }
29
+
30
+ type SwiftUIModifiersModule = {
31
+ disabled: (value: boolean) => unknown
32
+ }
33
+
34
+ export function createExpoUIMenuView({
35
+ swiftUI,
36
+ modifiers,
37
+ }: {
38
+ swiftUI: SwiftUIModule
39
+ modifiers: SwiftUIModifiersModule
40
+ }): ComponentType<ExpoMenuViewProps> {
41
+ const { Button, ContextMenu, Host, Menu, RNHostView, Section, Toggle } = swiftUI
42
+
43
+ function renderAction(
44
+ action: ExpoMenuAction,
45
+ onPressAction: ExpoMenuViewProps['onPressAction']
46
+ ): ReactNode {
47
+ if (action.attributes?.hidden) return null
48
+ const { subactions, displayInline, state, attributes, image, title } = action
49
+ const systemImage = typeof image === 'string' ? image : undefined
50
+
51
+ if (subactions && subactions.length > 0) {
52
+ const children = subactions.map((sub) => renderAction(sub, onPressAction))
53
+ if (displayInline) {
54
+ return (
55
+ <Section key={action.id} title={title}>
56
+ {children}
57
+ </Section>
58
+ )
59
+ }
60
+ return (
61
+ <Menu key={action.id} label={title} systemImage={systemImage}>
62
+ {children}
63
+ </Menu>
64
+ )
65
+ }
66
+
67
+ const fire = () => onPressAction?.({ nativeEvent: { event: action.id } })
68
+ const itemModifiers = attributes?.disabled ? [modifiers.disabled(true)] : undefined
69
+
70
+ if (state === 'on' || state === 'off') {
71
+ return (
72
+ <Toggle
73
+ key={action.id}
74
+ label={title}
75
+ systemImage={systemImage}
76
+ isOn={state === 'on'}
77
+ onIsOnChange={fire}
78
+ modifiers={itemModifiers}
79
+ />
80
+ )
81
+ }
82
+
83
+ return (
84
+ <Button
85
+ key={action.id}
86
+ label={title}
87
+ systemImage={systemImage}
88
+ role={attributes?.destructive ? 'destructive' : undefined}
89
+ modifiers={itemModifiers}
90
+ onPress={fire}
91
+ />
92
+ )
93
+ }
94
+
95
+ return function ExpoUIMenuView({
96
+ actions,
97
+ onPressAction,
98
+ shouldOpenOnLongPress,
99
+ title,
100
+ children,
101
+ }: ExpoMenuViewProps) {
102
+ const items = actions.map((action) => renderAction(action, onPressAction))
103
+ const body = title ? <Section title={title}>{items}</Section> : items
104
+ // RNHostView takes exactly one element, so the trigger children ride in a
105
+ // fragment
106
+ const trigger = (
107
+ <RNHostView matchContents>
108
+ <>{children}</>
109
+ </RNHostView>
110
+ )
111
+ return (
112
+ <Host ignoreSafeArea="all">
113
+ {shouldOpenOnLongPress ? (
114
+ <ContextMenu>
115
+ <ContextMenu.Trigger>{trigger}</ContextMenu.Trigger>
116
+ <ContextMenu.Items>{body}</ContextMenu.Items>
117
+ </ContextMenu>
118
+ ) : (
119
+ <Menu label={trigger}>{body}</Menu>
120
+ )}
121
+ </Host>
122
+ )
123
+ }
124
+ }
@@ -10,7 +10,7 @@ export {
10
10
  releaseExternalPressOwnership as unstable_releaseExternalPressOwnership,
11
11
  } from './gestureState'
12
12
  export { PressBoundary } from './PressBoundary'
13
- export type { PressBoundaryProps } from './PressBoundary'
13
+ export type { PressBoundaryProps } from './types'
14
14
  export {
15
15
  getGestureHandlerConfig,
16
16
  setupGestureHandler,
package/src/index.ts CHANGED
@@ -10,12 +10,10 @@
10
10
  * import '@tamagui/native/setup-gesture-handler'
11
11
  * import '@tamagui/native/setup-worklets'
12
12
  * import '@tamagui/native/setup-safe-area'
13
- * import '@tamagui/native/expo-linear-gradient'
14
13
  * import '@tamagui/native/setup-keyboard-controller'
15
14
  *
16
15
  * // Then use Tamagui components normally
17
16
  * // Sheet will automatically use native gestures when available
18
- * // LinearGradient will use expo-linear-gradient when installed
19
17
  * ```
20
18
  */
21
19
 
@@ -28,7 +26,6 @@ export type {
28
26
  SafeAreaInsets,
29
27
  SafeAreaFrame,
30
28
  SafeAreaMetrics,
31
- LinearGradientState,
32
29
  BurntState,
33
30
  NativePortalProps,
34
31
  NativePortalHostProps,
@@ -64,10 +61,6 @@ export type { WorkletsAccessor } from './workletsState'
64
61
  export { getSafeArea, hasSafeAreaSetup } from './safeAreaState'
65
62
  export type { SafeAreaAccessor } from './safeAreaState'
66
63
 
67
- // linear gradient
68
- export { getLinearGradient } from './linearGradientState'
69
- export type { LinearGradientAccessor } from './linearGradientState'
70
-
71
64
  // keyboard controller state exports (safe - no side effects)
72
65
  export {
73
66
  isKeyboardControllerEnabled,
@@ -1,4 +1,10 @@
1
1
  import type React from 'react'
2
2
  import { createContext } from 'react'
3
3
 
4
- export const NativeMenuContext: React.Context<boolean> = createContext(false)
4
+ // one context per runtime: core reads it and the menu packages provide it, so a
5
+ // second copy of this module (a bundled core, a duplicated install) must not
6
+ // split them into two contexts that never see each other
7
+ const KEY = '__tamagui_native_menu_context__'
8
+ const g = globalThis as typeof globalThis & { [KEY]?: React.Context<boolean> }
9
+
10
+ export const NativeMenuContext: React.Context<boolean> = (g[KEY] ??= createContext(false))
@@ -6,12 +6,20 @@
6
6
  */
7
7
 
8
8
  import { createExpoUIMenuAdapter } from './expoUIMenuAdapter'
9
+ import { createExpoUIMenuView } from './expoUIMenuView'
9
10
  import { registerNativeMenuAdapter } from './nativeMenuState'
11
+ import { Platform } from 'react-native'
10
12
 
11
13
  function setup(): void {
12
14
  let MenuView
13
15
  try {
14
- MenuView = require('@expo/ui/community/menu').MenuView
16
+ MenuView =
17
+ Platform.OS === 'ios'
18
+ ? createExpoUIMenuView({
19
+ swiftUI: require('@expo/ui/swift-ui'),
20
+ modifiers: require('@expo/ui/swift-ui/modifiers'),
21
+ })
22
+ : require('@expo/ui/community/menu').MenuView
15
23
  } catch (error) {
16
24
  if (process.env.NODE_ENV === 'development') {
17
25
  console.warn('Error setting up Expo UI native menus', error)
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Setup native portal support for Tamagui with One's native portals
3
+ * (One.UI.Portal and One.UI.PortalHost), an alternative to setup-teleport.
4
+ *
5
+ * Import this module at the top of your app entry point:
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import '@tamagui/native/setup-one-portal'
10
+ * ```
11
+ */
12
+
13
+ import { getPortal } from './portalState'
14
+
15
+ function setup(): void {
16
+ const g = globalThis as any
17
+ if (g.__tamagui_native_portal_setup) return
18
+ g.__tamagui_native_portal_setup = true
19
+
20
+ const { One } = require('one')
21
+ // one's portals keep their react tree without a provider and lay content out
22
+ // against the host's own size, so the host fills its parent.
23
+ g.__tamagui_teleport = {
24
+ Portal: One.UI.Portal,
25
+ PortalHost: One.UI.PortalHost,
26
+ hostStyle: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0 },
27
+ }
28
+ getPortal().set({ enabled: true, type: 'teleport' })
29
+ }
30
+
31
+ // run setup immediately on import
32
+ setup()
package/src/types.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ViewProps } from '@tamagui/react-native-types'
1
2
  import type { ReactNode } from 'react'
2
3
 
3
4
  export type NativePortalState = {
@@ -64,11 +65,6 @@ export type NativePortalProviderProps = {
64
65
  children: ReactNode
65
66
  }
66
67
 
67
- export interface LinearGradientState {
68
- enabled: boolean
69
- Component: any
70
- }
71
-
72
68
  export interface BurntState {
73
69
  enabled: boolean
74
70
  toast: ((options: any) => void) | null
@@ -85,3 +81,13 @@ export interface KeyboardControllerState {
85
81
  KeyboardEvents: any
86
82
  KeyboardStickyView: any
87
83
  }
84
+
85
+ export interface PressBoundaryProps extends ViewProps {
86
+ enabled?: boolean
87
+ /**
88
+ * Alias for enabling the boundary. The behavior is limited to Tamagui's
89
+ * shared press ownership and does not patch arbitrary RN bubbling.
90
+ */
91
+ stopPropagation?: boolean
92
+ debugName?: string | null
93
+ }
@@ -1,16 +1,15 @@
1
- import React from "react";
2
- import { View, type ViewProps } from "react-native";
3
- export interface PressBoundaryProps extends ViewProps {
4
- enabled?: boolean;
5
- /**
6
- * Alias for enabling the boundary. The behavior is limited to Tamagui's
7
- * shared press ownership and does not patch arbitrary RN bubbling.
8
- */
9
- stopPropagation?: boolean;
10
- debugName?: string | null;
11
- }
12
- export declare const PressBoundary: (props: PressBoundaryProps & {
13
- ref?: React.Ref<View>;
14
- }) => React.ReactNode;
1
+ import type { ReactNode, Ref } from "react";
2
+ import type { PressBoundaryProps } from "./types";
3
+ /**
4
+ * Renders children as-is.
5
+ *
6
+ * The boundary exists to arbitrate Tamagui's shared press ownership with
7
+ * react-native-gesture-handler, which only runs on native, so on web there is
8
+ * nothing to claim and no view worth adding. `ref` is accepted and ignored for
9
+ * the same reason: there is no host node here to hand back.
10
+ */
11
+ export declare function PressBoundary({ children }: PressBoundaryProps & {
12
+ ref?: Ref<unknown>;
13
+ }): ReactNode;
15
14
 
16
15
  //# sourceMappingURL=PressBoundary.d.ts.map