@tamagui/native 2.7.7 → 3.0.0-beta.1093.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/dist/cjs/PressBoundary.cjs +15 -80
- package/dist/cjs/PressBoundary.native.cjs +85 -0
- package/dist/cjs/PressBoundary.native.js +64 -82
- package/dist/cjs/PressBoundary.native.js.map +1 -1
- package/dist/cjs/burntState.cjs +28 -32
- package/dist/cjs/burntState.native.cjs +44 -0
- package/dist/cjs/burntState.native.js +28 -31
- package/dist/cjs/burntState.native.js.map +1 -1
- package/dist/cjs/components.cjs +34 -55
- package/dist/cjs/components.native.cjs +55 -0
- package/dist/cjs/components.native.js +34 -54
- package/dist/cjs/components.native.js.map +1 -1
- package/dist/cjs/expoUIMenuAdapter.cjs +239 -254
- package/dist/cjs/expoUIMenuAdapter.native.cjs +310 -0
- package/dist/cjs/expoUIMenuAdapter.native.js +282 -305
- package/dist/cjs/expoUIMenuAdapter.native.js.map +1 -1
- package/dist/cjs/gesture-handler.cjs +20 -22
- package/dist/cjs/gesture-handler.native.cjs +37 -0
- package/dist/cjs/gesture-handler.native.js +20 -21
- package/dist/cjs/gesture-handler.native.js.map +1 -1
- package/dist/cjs/gestureState.cjs +201 -207
- package/dist/cjs/gestureState.native.cjs +261 -0
- package/dist/cjs/gestureState.native.js +214 -219
- package/dist/cjs/gestureState.native.js.map +1 -1
- package/dist/cjs/globalState.cjs +30 -34
- package/dist/cjs/globalState.native.cjs +43 -0
- package/dist/cjs/globalState.native.js +30 -33
- package/dist/cjs/globalState.native.js.map +1 -1
- package/dist/cjs/index.cjs +33 -34
- package/dist/cjs/index.native.cjs +58 -0
- package/dist/cjs/index.native.js +33 -33
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/keyboardControllerState.cjs +27 -29
- package/dist/cjs/keyboardControllerState.native.cjs +49 -0
- package/dist/cjs/keyboardControllerState.native.js +27 -28
- package/dist/cjs/keyboardControllerState.native.js.map +1 -1
- package/dist/cjs/linearGradientState.cjs +27 -31
- package/dist/cjs/linearGradientState.native.cjs +43 -0
- package/dist/cjs/linearGradientState.native.js +27 -30
- package/dist/cjs/linearGradientState.native.js.map +1 -1
- package/dist/cjs/nativeMenuContext.cjs +14 -18
- package/dist/cjs/nativeMenuContext.native.cjs +27 -0
- package/dist/cjs/nativeMenuContext.native.js +14 -17
- package/dist/cjs/nativeMenuContext.native.js.map +1 -1
- package/dist/cjs/nativeMenuState.cjs +26 -28
- package/dist/cjs/nativeMenuState.native.cjs +46 -0
- package/dist/cjs/nativeMenuState.native.js +26 -27
- package/dist/cjs/nativeMenuState.native.js.map +1 -1
- package/dist/cjs/portalState.cjs +27 -31
- package/dist/cjs/portalState.native.cjs +43 -0
- package/dist/cjs/portalState.native.js +27 -30
- package/dist/cjs/portalState.native.js.map +1 -1
- package/dist/cjs/safeAreaState.cjs +76 -53
- package/dist/cjs/safeAreaState.native.cjs +100 -0
- package/dist/cjs/safeAreaState.native.js +78 -52
- package/dist/cjs/safeAreaState.native.js.map +1 -1
- package/dist/cjs/setup-burnt.cjs +14 -14
- package/dist/cjs/setup-burnt.native.cjs +19 -0
- package/dist/cjs/setup-burnt.native.js +14 -13
- package/dist/cjs/setup-burnt.native.js.map +1 -1
- package/dist/cjs/setup-expo-linear-gradient.cjs +13 -13
- package/dist/cjs/setup-expo-linear-gradient.native.cjs +18 -0
- package/dist/cjs/setup-expo-linear-gradient.native.js +13 -12
- package/dist/cjs/setup-expo-linear-gradient.native.js.map +1 -1
- package/dist/cjs/setup-expo-ui-menu.cjs +11 -13
- package/dist/cjs/setup-expo-ui-menu.native.cjs +17 -0
- package/dist/cjs/setup-expo-ui-menu.native.js +11 -12
- package/dist/cjs/setup-expo-ui-menu.native.js.map +1 -1
- package/dist/cjs/setup-gesture-handler.cjs +50 -57
- package/dist/cjs/setup-gesture-handler.native.cjs +71 -0
- package/dist/cjs/setup-gesture-handler.native.js +50 -56
- package/dist/cjs/setup-gesture-handler.native.js.map +1 -1
- package/dist/cjs/setup-keyboard-controller.native.cjs +27 -0
- package/dist/cjs/setup-keyboard-controller.native.js +22 -29
- package/dist/cjs/setup-keyboard-controller.native.js.map +1 -1
- package/dist/cjs/setup-safe-area.cjs +16 -3
- package/dist/cjs/setup-safe-area.native.cjs +27 -0
- package/dist/cjs/setup-safe-area.native.js +22 -16
- package/dist/cjs/setup-safe-area.native.js.map +1 -1
- package/dist/cjs/setup-teleport.cjs +15 -15
- package/dist/cjs/setup-teleport.native.cjs +20 -0
- package/dist/cjs/setup-teleport.native.js +15 -14
- package/dist/cjs/setup-teleport.native.js.map +1 -1
- package/dist/cjs/setup-worklets.cjs +18 -18
- package/dist/cjs/setup-worklets.native.cjs +23 -0
- package/dist/cjs/setup-worklets.native.js +18 -17
- package/dist/cjs/setup-worklets.native.js.map +1 -1
- package/dist/cjs/setup-zeego.cjs +17 -17
- package/dist/cjs/setup-zeego.native.cjs +22 -0
- package/dist/cjs/setup-zeego.native.js +17 -16
- package/dist/cjs/setup-zeego.native.js.map +1 -1
- package/dist/cjs/types.cjs +9 -11
- package/dist/cjs/types.native.cjs +18 -0
- package/dist/cjs/types.native.js +9 -10
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/cjs/workletsState.cjs +30 -34
- package/dist/cjs/workletsState.native.cjs +46 -0
- package/dist/cjs/workletsState.native.js +30 -33
- package/dist/cjs/workletsState.native.js.map +1 -1
- package/dist/esm/PressBoundary.mjs +5 -53
- package/dist/esm/PressBoundary.mjs.map +1 -1
- package/dist/esm/PressBoundary.native.js +48 -56
- package/dist/esm/PressBoundary.native.js.map +1 -1
- package/dist/esm/burntState.mjs +16 -14
- package/dist/esm/burntState.mjs.map +1 -1
- package/dist/esm/burntState.native.js +16 -14
- package/dist/esm/burntState.native.js.map +1 -1
- package/dist/esm/components.mjs +20 -37
- package/dist/esm/components.mjs.map +1 -1
- package/dist/esm/components.native.js +21 -38
- package/dist/esm/components.native.js.map +1 -1
- package/dist/esm/expoUIMenuAdapter.mjs +224 -228
- package/dist/esm/expoUIMenuAdapter.mjs.map +1 -1
- package/dist/esm/expoUIMenuAdapter.native.js +267 -280
- package/dist/esm/expoUIMenuAdapter.native.js.map +1 -1
- package/dist/esm/gesture-handler.mjs +3 -4
- package/dist/esm/gesture-handler.native.js +3 -4
- package/dist/esm/gestureState.mjs +185 -187
- package/dist/esm/gestureState.mjs.map +1 -1
- package/dist/esm/gestureState.native.js +198 -200
- package/dist/esm/gestureState.native.js.map +1 -1
- package/dist/esm/globalState.mjs +17 -16
- package/dist/esm/globalState.mjs.map +1 -1
- package/dist/esm/globalState.native.js +17 -16
- package/dist/esm/globalState.native.js.map +1 -1
- package/dist/esm/index.js +5 -6
- package/dist/esm/index.mjs +5 -6
- package/dist/esm/index.native.js +5 -6
- package/dist/esm/keyboardControllerState.mjs +13 -11
- package/dist/esm/keyboardControllerState.mjs.map +1 -1
- package/dist/esm/keyboardControllerState.native.js +13 -11
- package/dist/esm/keyboardControllerState.native.js.map +1 -1
- package/dist/esm/linearGradientState.mjs +15 -13
- package/dist/esm/linearGradientState.mjs.map +1 -1
- package/dist/esm/linearGradientState.native.js +15 -13
- package/dist/esm/linearGradientState.native.js.map +1 -1
- package/dist/esm/nativeMenuContext.mjs +2 -0
- package/dist/esm/nativeMenuContext.mjs.map +1 -1
- package/dist/esm/nativeMenuContext.native.js +2 -0
- package/dist/esm/nativeMenuContext.native.js.map +1 -1
- package/dist/esm/nativeMenuState.mjs +13 -11
- package/dist/esm/nativeMenuState.mjs.map +1 -1
- package/dist/esm/nativeMenuState.native.js +13 -11
- package/dist/esm/nativeMenuState.native.js.map +1 -1
- package/dist/esm/portalState.mjs +15 -13
- package/dist/esm/portalState.mjs.map +1 -1
- package/dist/esm/portalState.native.js +15 -13
- package/dist/esm/portalState.native.js.map +1 -1
- package/dist/esm/safeAreaState.mjs +64 -38
- package/dist/esm/safeAreaState.mjs.map +1 -1
- package/dist/esm/safeAreaState.native.js +66 -38
- package/dist/esm/safeAreaState.native.js.map +1 -1
- package/dist/esm/setup-burnt.mjs +20 -13
- package/dist/esm/setup-burnt.mjs.map +1 -1
- package/dist/esm/setup-burnt.native.js +20 -13
- package/dist/esm/setup-burnt.native.js.map +1 -1
- package/dist/esm/setup-expo-linear-gradient.mjs +19 -12
- package/dist/esm/setup-expo-linear-gradient.mjs.map +1 -1
- package/dist/esm/setup-expo-linear-gradient.native.js +19 -12
- package/dist/esm/setup-expo-linear-gradient.native.js.map +1 -1
- package/dist/esm/setup-expo-ui-menu.mjs +17 -12
- package/dist/esm/setup-expo-ui-menu.mjs.map +1 -1
- package/dist/esm/setup-expo-ui-menu.native.js +17 -12
- package/dist/esm/setup-expo-ui-menu.native.js.map +1 -1
- package/dist/esm/setup-gesture-handler.mjs +42 -40
- package/dist/esm/setup-gesture-handler.mjs.map +1 -1
- package/dist/esm/setup-gesture-handler.native.js +42 -40
- package/dist/esm/setup-gesture-handler.native.js.map +1 -1
- package/dist/esm/setup-keyboard-controller.mjs +0 -2
- package/dist/esm/setup-keyboard-controller.native.js +28 -29
- package/dist/esm/setup-keyboard-controller.native.js.map +1 -1
- package/dist/esm/setup-safe-area.mjs +0 -4
- package/dist/esm/setup-safe-area.native.js +23 -22
- package/dist/esm/setup-safe-area.native.js.map +1 -1
- package/dist/esm/setup-teleport.mjs +21 -14
- package/dist/esm/setup-teleport.mjs.map +1 -1
- package/dist/esm/setup-teleport.native.js +21 -14
- package/dist/esm/setup-teleport.native.js.map +1 -1
- package/dist/esm/setup-worklets.mjs +24 -17
- package/dist/esm/setup-worklets.mjs.map +1 -1
- package/dist/esm/setup-worklets.native.js +24 -17
- package/dist/esm/setup-worklets.native.js.map +1 -1
- package/dist/esm/setup-zeego.mjs +23 -16
- package/dist/esm/setup-zeego.mjs.map +1 -1
- package/dist/esm/setup-zeego.native.js +23 -16
- package/dist/esm/setup-zeego.native.js.map +1 -1
- package/dist/esm/types.mjs +0 -2
- package/dist/esm/types.native.js +0 -2
- package/dist/esm/workletsState.mjs +18 -16
- package/dist/esm/workletsState.mjs.map +1 -1
- package/dist/esm/workletsState.native.js +18 -16
- package/dist/esm/workletsState.native.js.map +1 -1
- package/package.json +87 -8
- package/src/PressBoundary.native.tsx +75 -0
- package/src/PressBoundary.tsx +16 -80
- package/src/expoUIMenuAdapter.tsx +1 -2
- package/src/gesture-handler.ts +1 -1
- package/src/gestureState.ts +2 -2
- package/src/index.ts +1 -1
- package/src/safeAreaState.ts +59 -27
- package/src/setup-safe-area.ts +27 -22
- package/src/setup-safe-area.web.ts +2 -0
- package/src/types.ts +12 -0
- package/types/PressBoundary.d.ts +13 -12
- package/types/PressBoundary.d.ts.map +2 -2
- package/types/PressBoundary.native.d.ts +8 -0
- package/types/PressBoundary.native.d.ts.map +11 -0
- package/types/expoUIMenuAdapter.d.ts.map +2 -2
- package/types/gesture-handler.d.ts +1 -1
- package/types/gesture-handler.d.ts.map +1 -1
- package/types/gestureState.d.ts.map +1 -1
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +2 -2
- package/types/safeAreaState.d.ts +5 -2
- package/types/safeAreaState.d.ts.map +2 -2
- package/types/setup-safe-area.d.ts.map +1 -1
- package/types/setup-safe-area.web.d.ts +3 -0
- package/types/setup-safe-area.web.d.ts.map +11 -0
- package/types/types.d.ts +11 -0
- package/types/types.d.ts.map +2 -2
- package/.turbo/turbo-build.log +0 -2
- package/dist/esm/gesture-handler.mjs.map +0 -1
- package/dist/esm/gesture-handler.native.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/index.mjs.map +0 -1
- package/dist/esm/index.native.js.map +0 -1
- package/dist/esm/setup-keyboard-controller.mjs.map +0 -1
- package/dist/esm/setup-safe-area.mjs.map +0 -1
- package/dist/esm/types.mjs.map +0 -1
- package/dist/esm/types.native.js.map +0 -1
- package/tsconfig.json +0 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"workletsState.native.js","names":[],"sources":["esm/workletsState.native.js"],"sourcesContent":["import { createGlobalState } from \"./globalState\";\nvar state = createGlobalState(`worklets`, {\n enabled: false,\n Worklets: null,\n useRunOnJS: null,\n useWorklet: null,\n createWorkletContextValue: null\n});\nfunction getWorklets() {\n return {\n get isEnabled() {\n return state.get().enabled;\n },\n get state() {\n return state.get();\n },\n set(updates) {\n Object.assign(state.get(), updates);\n }\n };\n}\nexport {\n getWorklets\n};\n//# sourceMappingURL=workletsState.js.map\n"],"mappings":";;;AACA,IAAI,QAAQ,kBAAkB,YAAY;CACxC,SAAS;CACT,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,2BAA2B;AAC7B,CAAC;AACD,SAAS,cAAc;CACrB,OAAO;EACL,IAAI,YAAY;GACd,OAAO,MAAM,IAAI,CAAC,CAAC;EACrB;EACA,IAAI,QAAQ;GACV,OAAO,MAAM,IAAI;EACnB;EACA,IAAI,SAAS;GACX,OAAO,OAAO,MAAM,IAAI,GAAG,OAAO;EACpC;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/native",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-beta.1093.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": [
|
|
7
8
|
"**/setup-*",
|
|
8
9
|
"**/gesture-handler*"
|
|
9
10
|
],
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
"types",
|
|
14
|
+
"dist",
|
|
15
|
+
"gesture-handler",
|
|
16
|
+
"gesture-handler.cjs",
|
|
17
|
+
"setup-burnt",
|
|
18
|
+
"setup-burnt.cjs",
|
|
19
|
+
"setup-expo-linear-gradient",
|
|
20
|
+
"setup-expo-linear-gradient.cjs",
|
|
21
|
+
"setup-expo-ui-menu",
|
|
22
|
+
"setup-expo-ui-menu.cjs",
|
|
23
|
+
"setup-gesture-handler",
|
|
24
|
+
"setup-gesture-handler.cjs",
|
|
25
|
+
"setup-keyboard-controller",
|
|
26
|
+
"setup-keyboard-controller.cjs",
|
|
27
|
+
"setup-safe-area",
|
|
28
|
+
"setup-safe-area.cjs",
|
|
29
|
+
"setup-teleport",
|
|
30
|
+
"setup-teleport.cjs",
|
|
31
|
+
"setup-worklets",
|
|
32
|
+
"setup-worklets.cjs",
|
|
33
|
+
"setup-zeego",
|
|
34
|
+
"setup-zeego.cjs"
|
|
35
|
+
],
|
|
10
36
|
"main": "dist/cjs",
|
|
11
37
|
"module": "dist/esm",
|
|
12
38
|
"types": "./types/index.d.ts",
|
|
@@ -155,20 +181,73 @@
|
|
|
155
181
|
"clean": "tamagui-build clean",
|
|
156
182
|
"clean:build": "tamagui-build clean:build"
|
|
157
183
|
},
|
|
184
|
+
"dependencies": {
|
|
185
|
+
"@tamagui/compose-refs": "3.0.0-beta.1093.1",
|
|
186
|
+
"@tamagui/react-native-types": "3.0.0-beta.1093.1"
|
|
187
|
+
},
|
|
158
188
|
"devDependencies": {
|
|
159
|
-
"@
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"react
|
|
164
|
-
"react-native
|
|
189
|
+
"@expo/ui": "~57.0.12",
|
|
190
|
+
"@tamagui/build": "3.0.0-beta.1093.1",
|
|
191
|
+
"burnt": "^0.13.0",
|
|
192
|
+
"expo-linear-gradient": "~57.0.1",
|
|
193
|
+
"react": "19.2.3",
|
|
194
|
+
"react-native": "0.86.2",
|
|
195
|
+
"react-native-gesture-handler": "~2.32.0",
|
|
196
|
+
"react-native-keyboard-controller": "1.21.11",
|
|
165
197
|
"react-native-safe-area-context": "~5.7.0",
|
|
166
198
|
"react-native-teleport": "^1.0.0",
|
|
199
|
+
"react-native-web": "~0.21.0",
|
|
167
200
|
"react-native-worklets-core": "^1.0.0",
|
|
168
201
|
"zeego": "^3.0.0"
|
|
169
202
|
},
|
|
170
203
|
"peerDependencies": {
|
|
171
|
-
"
|
|
204
|
+
"@expo/ui": "*",
|
|
205
|
+
"burnt": "*",
|
|
206
|
+
"expo-linear-gradient": "*",
|
|
207
|
+
"react": "*",
|
|
208
|
+
"react-native": "*",
|
|
209
|
+
"react-native-gesture-handler": "*",
|
|
210
|
+
"react-native-keyboard-controller": "*",
|
|
211
|
+
"react-native-safe-area-context": "*",
|
|
212
|
+
"react-native-teleport": "*",
|
|
213
|
+
"react-native-web": "*",
|
|
214
|
+
"react-native-worklets-core": "*",
|
|
215
|
+
"zeego": "*"
|
|
216
|
+
},
|
|
217
|
+
"peerDependenciesMeta": {
|
|
218
|
+
"@expo/ui": {
|
|
219
|
+
"optional": true
|
|
220
|
+
},
|
|
221
|
+
"burnt": {
|
|
222
|
+
"optional": true
|
|
223
|
+
},
|
|
224
|
+
"react-native": {
|
|
225
|
+
"optional": true
|
|
226
|
+
},
|
|
227
|
+
"react-native-web": {
|
|
228
|
+
"optional": true
|
|
229
|
+
},
|
|
230
|
+
"expo-linear-gradient": {
|
|
231
|
+
"optional": true
|
|
232
|
+
},
|
|
233
|
+
"react-native-gesture-handler": {
|
|
234
|
+
"optional": true
|
|
235
|
+
},
|
|
236
|
+
"react-native-keyboard-controller": {
|
|
237
|
+
"optional": true
|
|
238
|
+
},
|
|
239
|
+
"react-native-safe-area-context": {
|
|
240
|
+
"optional": true
|
|
241
|
+
},
|
|
242
|
+
"react-native-teleport": {
|
|
243
|
+
"optional": true
|
|
244
|
+
},
|
|
245
|
+
"react-native-worklets-core": {
|
|
246
|
+
"optional": true
|
|
247
|
+
},
|
|
248
|
+
"zeego": {
|
|
249
|
+
"optional": true
|
|
250
|
+
}
|
|
172
251
|
},
|
|
173
252
|
"repository": {
|
|
174
253
|
"type": "git",
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createRefComponent } from '@tamagui/compose-refs'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { View } 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<View> }
|
|
27
|
+
) => React.ReactNode = createRefComponent<View, 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
|
+
)
|
package/src/PressBoundary.tsx
CHANGED
|
@@ -1,81 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function composeFirst<T extends (...args: any[]) => void>(ours: T, theirs?: T) {
|
|
20
|
-
return (...args: Parameters<T>) => {
|
|
21
|
-
ours(...args)
|
|
22
|
-
theirs?.(...args)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function composeLast<T extends (...args: any[]) => void>(theirs: T | undefined, ours: T) {
|
|
27
|
-
return (...args: Parameters<T>) => {
|
|
28
|
-
theirs?.(...args)
|
|
29
|
-
ours(...args)
|
|
30
|
-
}
|
|
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}</>
|
|
31
17
|
}
|
|
32
|
-
|
|
33
|
-
export const PressBoundary: React.ForwardRefExoticComponent<
|
|
34
|
-
PressBoundaryProps & React.RefAttributes<View>
|
|
35
|
-
> = React.forwardRef<View, PressBoundaryProps>(function PressBoundary(
|
|
36
|
-
{
|
|
37
|
-
enabled,
|
|
38
|
-
stopPropagation,
|
|
39
|
-
debugName,
|
|
40
|
-
onTouchStart,
|
|
41
|
-
onTouchEnd,
|
|
42
|
-
onTouchCancel,
|
|
43
|
-
onResponderGrant,
|
|
44
|
-
onResponderRelease,
|
|
45
|
-
onResponderTerminate,
|
|
46
|
-
...props
|
|
47
|
-
},
|
|
48
|
-
forwardedRef
|
|
49
|
-
) {
|
|
50
|
-
const tokenRef = React.useRef<ExternalPressOwnershipToken | null>(null)
|
|
51
|
-
const isEnabled = enabled ?? stopPropagation ?? true
|
|
52
|
-
|
|
53
|
-
const claim = React.useCallback((): void => {
|
|
54
|
-
if (!isEnabled) return
|
|
55
|
-
if (tokenRef.current) {
|
|
56
|
-
releaseExternalPressOwnership(tokenRef.current, debugName)
|
|
57
|
-
}
|
|
58
|
-
tokenRef.current = claimExternalPressOwnership(debugName)
|
|
59
|
-
}, [debugName, isEnabled])
|
|
60
|
-
|
|
61
|
-
const release = React.useCallback((): void => {
|
|
62
|
-
if (!tokenRef.current) return
|
|
63
|
-
releaseExternalPressOwnership(tokenRef.current, debugName)
|
|
64
|
-
tokenRef.current = null
|
|
65
|
-
}, [debugName])
|
|
66
|
-
|
|
67
|
-
React.useEffect(() => release, [release])
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<View
|
|
71
|
-
ref={forwardedRef}
|
|
72
|
-
{...props}
|
|
73
|
-
onTouchStart={composeFirst(claim, onTouchStart)}
|
|
74
|
-
onTouchEnd={composeLast(onTouchEnd, release)}
|
|
75
|
-
onTouchCancel={composeLast(onTouchCancel, release)}
|
|
76
|
-
onResponderGrant={composeFirst(claim, onResponderGrant)}
|
|
77
|
-
onResponderRelease={composeLast(onResponderRelease, release)}
|
|
78
|
-
onResponderTerminate={composeLast(onResponderTerminate, release)}
|
|
79
|
-
/>
|
|
80
|
-
)
|
|
81
|
-
})
|
|
@@ -74,8 +74,7 @@ const warnedUnsupported = new Set<string>()
|
|
|
74
74
|
// @expo/ui's MenuAction carries no subtitle, and its MenuView has no preview or
|
|
75
75
|
// auxiliary view. these are decorations on a menu that is otherwise complete, so
|
|
76
76
|
// drop them and warn once. throwing took down the whole app for an optional
|
|
77
|
-
// embellishment
|
|
78
|
-
// cannot avoid it without forking its markup per adapter.
|
|
77
|
+
// embellishment. apps cannot avoid this without forking their markup per adapter.
|
|
79
78
|
function warnUnsupported(feature: string) {
|
|
80
79
|
if (warnedUnsupported.has(feature) || process.env.NODE_ENV === 'production') {
|
|
81
80
|
return
|
package/src/gesture-handler.ts
CHANGED
|
@@ -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 './
|
|
13
|
+
export type { PressBoundaryProps } from './types'
|
|
14
14
|
export {
|
|
15
15
|
getGestureHandlerConfig,
|
|
16
16
|
setupGestureHandler,
|
package/src/gestureState.ts
CHANGED
|
@@ -358,7 +358,7 @@ export function getGestureHandler(): GestureHandlerAccessor {
|
|
|
358
358
|
const dy = touch.absoluteY - flags.moveStartY
|
|
359
359
|
if (dx * dx + dy * dy <= PRESS_MOVE_CANCEL_DISTANCE_SQ) return
|
|
360
360
|
// finger has travelled far enough to be a scroll/drag, not a tap.
|
|
361
|
-
// release the
|
|
361
|
+
// release the press state now (mid-scroll, so it doesn't stay stuck)
|
|
362
362
|
// and make onEnd skip onPress on finger lift.
|
|
363
363
|
flags.cancelledByMove = true
|
|
364
364
|
if (flags.pressInTimer) {
|
|
@@ -385,7 +385,7 @@ export function getGestureHandler(): GestureHandlerAccessor {
|
|
|
385
385
|
// we already fired onPressIn but lost ownership before finalize
|
|
386
386
|
// (e.g. finger dragged onto a sibling pressable and that one
|
|
387
387
|
// claimed ownership). fire onPressOut so callers can clear their
|
|
388
|
-
// press state - otherwise
|
|
388
|
+
// press state - otherwise the press clause stays stuck on this view.
|
|
389
389
|
flags.didPressIn = false
|
|
390
390
|
config.onPressOut?.(e)
|
|
391
391
|
}
|
package/src/index.ts
CHANGED
|
@@ -61,7 +61,7 @@ export { getWorklets } from './workletsState'
|
|
|
61
61
|
export type { WorkletsAccessor } from './workletsState'
|
|
62
62
|
|
|
63
63
|
// safe area
|
|
64
|
-
export { getSafeArea } from './safeAreaState'
|
|
64
|
+
export { getSafeArea, hasSafeAreaSetup } from './safeAreaState'
|
|
65
65
|
export type { SafeAreaAccessor } from './safeAreaState'
|
|
66
66
|
|
|
67
67
|
// linear gradient
|
package/src/safeAreaState.ts
CHANGED
|
@@ -2,49 +2,81 @@ import { createGlobalState } from './globalState'
|
|
|
2
2
|
import type { SafeAreaState, SafeAreaInsets, SafeAreaFrame } from './types'
|
|
3
3
|
|
|
4
4
|
const state = createGlobalState<SafeAreaState>(`safe_area`, {
|
|
5
|
+
didSetup: false,
|
|
5
6
|
enabled: false,
|
|
6
7
|
useSafeAreaInsets: null,
|
|
7
8
|
useSafeAreaFrame: null,
|
|
8
9
|
initialMetrics: null,
|
|
9
10
|
})
|
|
10
11
|
|
|
12
|
+
const subscriptions = createGlobalState(`safe_area_subscriptions`, {
|
|
13
|
+
enabled: true,
|
|
14
|
+
listeners: new Set<() => void>(),
|
|
15
|
+
})
|
|
16
|
+
|
|
11
17
|
const defaultInsets: SafeAreaInsets = { top: 0, right: 0, bottom: 0, left: 0 }
|
|
12
18
|
const defaultFrame: SafeAreaFrame = { x: 0, y: 0, width: 0, height: 0 }
|
|
13
19
|
|
|
14
20
|
export interface SafeAreaAccessor {
|
|
21
|
+
readonly didSetup: boolean
|
|
15
22
|
readonly isEnabled: boolean
|
|
16
23
|
readonly state: SafeAreaState
|
|
17
24
|
set(updates: Partial<SafeAreaState>): void
|
|
18
|
-
|
|
25
|
+
subscribe(listener: () => void): () => void
|
|
26
|
+
/** get the current insets snapshot */
|
|
19
27
|
getInsets(): SafeAreaInsets
|
|
20
|
-
/**
|
|
28
|
+
/** get the current frame snapshot */
|
|
21
29
|
getFrame(): SafeAreaFrame
|
|
22
30
|
}
|
|
23
31
|
|
|
32
|
+
const safeArea: SafeAreaAccessor = {
|
|
33
|
+
get didSetup() {
|
|
34
|
+
return state.get().didSetup
|
|
35
|
+
},
|
|
36
|
+
get isEnabled() {
|
|
37
|
+
return state.get().enabled
|
|
38
|
+
},
|
|
39
|
+
get state() {
|
|
40
|
+
return state.get()
|
|
41
|
+
},
|
|
42
|
+
set(updates) {
|
|
43
|
+
const current = state.get()
|
|
44
|
+
const previousMetrics = current.initialMetrics
|
|
45
|
+
Object.assign(current, updates)
|
|
46
|
+
if (
|
|
47
|
+
updates.initialMetrics !== undefined &&
|
|
48
|
+
current.initialMetrics !== previousMetrics
|
|
49
|
+
) {
|
|
50
|
+
subscriptions.get().listeners.forEach((listener) => listener())
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
subscribe(listener) {
|
|
54
|
+
const listeners = subscriptions.get().listeners
|
|
55
|
+
listeners.add(listener)
|
|
56
|
+
return () => {
|
|
57
|
+
listeners.delete(listener)
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
getInsets() {
|
|
61
|
+
const current = state.get()
|
|
62
|
+
if (!current.enabled || !current.initialMetrics) {
|
|
63
|
+
return defaultInsets
|
|
64
|
+
}
|
|
65
|
+
return current.initialMetrics.insets
|
|
66
|
+
},
|
|
67
|
+
getFrame() {
|
|
68
|
+
const current = state.get()
|
|
69
|
+
if (!current.enabled || !current.initialMetrics) {
|
|
70
|
+
return defaultFrame
|
|
71
|
+
}
|
|
72
|
+
return current.initialMetrics.frame
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
|
|
24
76
|
export function getSafeArea(): SafeAreaAccessor {
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return state.get()
|
|
31
|
-
},
|
|
32
|
-
set(updates: Partial<SafeAreaState>) {
|
|
33
|
-
Object.assign(state.get(), updates)
|
|
34
|
-
},
|
|
35
|
-
getInsets() {
|
|
36
|
-
const s = state.get()
|
|
37
|
-
if (!s.enabled || !s.initialMetrics) {
|
|
38
|
-
return defaultInsets
|
|
39
|
-
}
|
|
40
|
-
return s.initialMetrics.insets
|
|
41
|
-
},
|
|
42
|
-
getFrame() {
|
|
43
|
-
const s = state.get()
|
|
44
|
-
if (!s.enabled || !s.initialMetrics) {
|
|
45
|
-
return defaultFrame
|
|
46
|
-
}
|
|
47
|
-
return s.initialMetrics.frame
|
|
48
|
-
},
|
|
49
|
-
}
|
|
77
|
+
return safeArea
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function hasSafeAreaSetup(): boolean {
|
|
81
|
+
return state.get().didSetup
|
|
50
82
|
}
|
package/src/setup-safe-area.ts
CHANGED
|
@@ -22,35 +22,40 @@
|
|
|
22
22
|
* On web, this is a no-op since CSS env(safe-area-inset-*) values work natively.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
+
import { useLayoutEffect } from 'react'
|
|
26
|
+
import {
|
|
27
|
+
initialWindowMetrics,
|
|
28
|
+
useSafeAreaFrame,
|
|
29
|
+
useSafeAreaInsets,
|
|
30
|
+
} from 'react-native-safe-area-context'
|
|
25
31
|
import { getSafeArea } from './safeAreaState'
|
|
26
32
|
|
|
27
33
|
function setup() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const g = globalThis as any
|
|
34
|
-
if (g.__tamagui_native_safe_area_setup_complete) {
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
g.__tamagui_native_safe_area_setup_complete = true
|
|
34
|
+
const safeArea = getSafeArea()
|
|
35
|
+
safeArea.set({ didSetup: true })
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const
|
|
37
|
+
const useTrackedSafeAreaInsets = () => {
|
|
38
|
+
const insets = useSafeAreaInsets()
|
|
39
|
+
const frame = useSafeAreaFrame()
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
useLayoutEffect(() => {
|
|
42
|
+
safeArea.set({
|
|
43
|
+
initialMetrics: {
|
|
44
|
+
insets,
|
|
45
|
+
frame,
|
|
46
|
+
},
|
|
49
47
|
})
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
}, [insets, frame])
|
|
49
|
+
|
|
50
|
+
return insets
|
|
53
51
|
}
|
|
52
|
+
|
|
53
|
+
safeArea.set({
|
|
54
|
+
enabled: true,
|
|
55
|
+
useSafeAreaInsets: useTrackedSafeAreaInsets,
|
|
56
|
+
useSafeAreaFrame,
|
|
57
|
+
initialMetrics: initialWindowMetrics,
|
|
58
|
+
})
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
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 = {
|
|
@@ -44,6 +45,7 @@ export interface SafeAreaMetrics {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
export interface SafeAreaState {
|
|
48
|
+
didSetup: boolean
|
|
47
49
|
enabled: boolean
|
|
48
50
|
useSafeAreaInsets: (() => SafeAreaInsets) | null
|
|
49
51
|
useSafeAreaFrame: (() => SafeAreaFrame) | null
|
|
@@ -84,3 +86,13 @@ export interface KeyboardControllerState {
|
|
|
84
86
|
KeyboardEvents: any
|
|
85
87
|
KeyboardStickyView: any
|
|
86
88
|
}
|
|
89
|
+
|
|
90
|
+
export interface PressBoundaryProps extends ViewProps {
|
|
91
|
+
enabled?: boolean
|
|
92
|
+
/**
|
|
93
|
+
* Alias for enabling the boundary. The behavior is limited to Tamagui's
|
|
94
|
+
* shared press ownership and does not patch arbitrary RN bubbling.
|
|
95
|
+
*/
|
|
96
|
+
stopPropagation?: boolean
|
|
97
|
+
debugName?: string | null
|
|
98
|
+
}
|
package/types/PressBoundary.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
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;
|
|
13
14
|
|
|
14
15
|
//# sourceMappingURL=PressBoundary.d.ts.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"mappings": "AAAA,
|
|
2
|
+
"mappings": "AAAA,cAAc,WAAW,WAAW;AAEpC,cAAc,0BAA0B;;;;;;;;;AAUxC,OAAO,iBAAS,cAAc,EAC5B,YACC,qBAAqB;CAAE,MAAM;IAAiB",
|
|
3
3
|
"names": [],
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/PressBoundary.tsx"
|
|
6
6
|
],
|
|
7
7
|
"version": 3,
|
|
8
8
|
"sourcesContent": [
|
|
9
|
-
"import
|
|
9
|
+
"import type { ReactNode, Ref } from 'react'\n\nimport type { PressBoundaryProps } from './types'\n\n/**\n * Renders children as-is.\n *\n * The boundary exists to arbitrate Tamagui's shared press ownership with\n * react-native-gesture-handler, which only runs on native, so on web there is\n * nothing to claim and no view worth adding. `ref` is accepted and ignored for\n * the same reason: there is no host node here to hand back.\n */\nexport function PressBoundary({\n children,\n}: PressBoundaryProps & { ref?: Ref<unknown> }): ReactNode {\n return <>{children}</>\n}\n"
|
|
10
10
|
]
|
|
11
11
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import type { PressBoundaryProps } from "./types";
|
|
4
|
+
export declare const PressBoundary: (props: PressBoundaryProps & {
|
|
5
|
+
ref?: React.Ref<View>;
|
|
6
|
+
}) => React.ReactNode;
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=PressBoundary.native.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AACA,OAAO,WAAW;AAClB,SAAS,YAAY;AAMrB,cAAc,0BAA0B;AAgBxC,OAAO,cAAM,gBACX,OAAO,qBAAqB;CAAE,MAAM,MAAM,IAAI;MAC3C,MAAM",
|
|
3
|
+
"names": [],
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/PressBoundary.native.tsx"
|
|
6
|
+
],
|
|
7
|
+
"version": 3,
|
|
8
|
+
"sourcesContent": [
|
|
9
|
+
"import { createRefComponent } from '@tamagui/compose-refs'\nimport React from 'react'\nimport { View } from 'react-native'\nimport {\n claimExternalPressOwnership,\n releaseExternalPressOwnership,\n type ExternalPressOwnershipToken,\n} from './gestureState'\nimport type { PressBoundaryProps } from './types'\n\nfunction composeFirst<T extends (...args: any[]) => void>(ours: T, theirs?: T) {\n return (...args: Parameters<T>) => {\n ours(...args)\n theirs?.(...args)\n }\n}\n\nfunction composeLast<T extends (...args: any[]) => void>(theirs: T | undefined, ours: T) {\n return (...args: Parameters<T>) => {\n theirs?.(...args)\n ours(...args)\n }\n}\n\nexport const PressBoundary: (\n props: PressBoundaryProps & { ref?: React.Ref<View> }\n) => React.ReactNode = createRefComponent<View, PressBoundaryProps>(\n function PressBoundary(\n {\n enabled,\n stopPropagation,\n debugName,\n onTouchStart,\n onTouchEnd,\n onTouchCancel,\n onResponderGrant,\n onResponderRelease,\n onResponderTerminate,\n ...props\n },\n forwardedRef\n ) {\n const tokenRef = React.useRef<ExternalPressOwnershipToken | null>(null)\n const isEnabled = enabled ?? stopPropagation ?? true\n\n const claim = React.useCallback((): void => {\n if (!isEnabled) return\n if (tokenRef.current) {\n releaseExternalPressOwnership(tokenRef.current, debugName)\n }\n tokenRef.current = claimExternalPressOwnership(debugName)\n }, [debugName, isEnabled])\n\n const release = React.useCallback((): void => {\n if (!tokenRef.current) return\n releaseExternalPressOwnership(tokenRef.current, debugName)\n tokenRef.current = null\n }, [debugName])\n\n React.useEffect(() => release, [release])\n\n return (\n <View\n ref={forwardedRef}\n {...props}\n onTouchStart={composeFirst(claim, onTouchStart)}\n onTouchEnd={composeLast(onTouchEnd, release)}\n onTouchCancel={composeLast(onTouchCancel, release)}\n onResponderGrant={composeFirst(claim, onResponderGrant)}\n onResponderRelease={composeLast(onResponderRelease, release)}\n onResponderTerminate={composeLast(onResponderTerminate, release)}\n />\n )\n }\n)\n"
|
|
10
|
+
]
|
|
11
|
+
}
|