WIP
This commit is contained in:
committed by
Oleksii Bulenok
parent
3d39ca0c0c
commit
95ce988fb7
+1
-1
@@ -234,7 +234,7 @@
|
|||||||
"react-native-device-attest": "^0.1.6",
|
"react-native-device-attest": "^0.1.6",
|
||||||
"react-native-drawer-layout": "^4.2.3",
|
"react-native-drawer-layout": "^4.2.3",
|
||||||
"react-native-edge-to-edge": "^1.8.1",
|
"react-native-edge-to-edge": "^1.8.1",
|
||||||
"react-native-gesture-handler": "~2.32.0",
|
"react-native-gesture-handler": "~3.1.0",
|
||||||
"react-native-keyboard-controller": "1.21.9",
|
"react-native-keyboard-controller": "1.21.9",
|
||||||
"react-native-mmkv": "^3.3.3",
|
"react-native-mmkv": "^3.3.3",
|
||||||
"react-native-pager-view": "6.8.0",
|
"react-native-pager-view": "6.8.0",
|
||||||
|
|||||||
@@ -36,3 +36,12 @@ index 38470a658878a63919186257041098747ec55473..b9d25798c9be229efeb676166f89bfbc
|
|||||||
if (open) {
|
if (open) {
|
||||||
runOnJS(onOpen)();
|
runOnJS(onOpen)();
|
||||||
} else {
|
} else {
|
||||||
|
diff --git a/lib/typescript/src/types.d.ts b/lib/typescript/src/types.d.ts
|
||||||
|
--- a/lib/typescript/src/types.d.ts
|
||||||
|
+++ b/lib/typescript/src/types.d.ts
|
||||||
|
@@ -1,4 +1,4 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import type { StyleProp, View, ViewStyle } from 'react-native';
|
||||||
|
-import type { PanGesture } from 'react-native-gesture-handler';
|
||||||
|
+import type { LegacyPanGesture as PanGesture } from 'react-native-gesture-handler';
|
||||||
|
import type { SharedValue } from 'react-native-reanimated';
|
||||||
|
|||||||
Generated
+13
-42
@@ -228,7 +228,7 @@ patchedDependencies:
|
|||||||
expo@57.0.8: 1722861d12907a2d412d04230545b2fcbfa5547a79f99d763cb3e8de6f3a6f2a
|
expo@57.0.8: 1722861d12907a2d412d04230545b2fcbfa5547a79f99d763cb3e8de6f3a6f2a
|
||||||
react-native-date-picker@5.0.13: 92943fb79d17d7342a29bbb12b0d8ee3cf6f7bca12ed322dc8d124a3e9fb75bd
|
react-native-date-picker@5.0.13: 92943fb79d17d7342a29bbb12b0d8ee3cf6f7bca12ed322dc8d124a3e9fb75bd
|
||||||
react-native-dotenv@3.4.11: 16b34eb974399935d3cf7c2526534f906991ccd876215176658347059cdd2021
|
react-native-dotenv@3.4.11: 16b34eb974399935d3cf7c2526534f906991ccd876215176658347059cdd2021
|
||||||
react-native-drawer-layout@4.2.3: 74f2c043cc22ab87054f219e7c7373a509b779b18bfa79d27e7d051d73355130
|
react-native-drawer-layout@4.2.3: 2a67e397c87df9fb947b1931c9b00724b802a8dca5d3013617e6155f1ae3188e
|
||||||
react-native-keyboard-controller@1.21.9: ac52bf7502ff3ad34a8594b5e1a916b96bf87a2523b6abc87c31f03607d52271
|
react-native-keyboard-controller@1.21.9: ac52bf7502ff3ad34a8594b5e1a916b96bf87a2523b6abc87c31f03607d52271
|
||||||
react-native-pager-view@6.8.0: c8316acd33c9aef6531e8c272c2bfab7bd02af1255969eeaab2bad5ab48531cc
|
react-native-pager-view@6.8.0: c8316acd33c9aef6531e8c272c2bfab7bd02af1255969eeaab2bad5ab48531cc
|
||||||
react-native-screens@4.26.2: ba3295d44434a729f143a6b2c24e4a9b2f911ab200b2bc47e46cdfeaa1536f7c
|
react-native-screens@4.26.2: ba3295d44434a729f143a6b2c24e4a9b2f911ab200b2bc47e46cdfeaa1536f7c
|
||||||
@@ -640,13 +640,13 @@ importers:
|
|||||||
version: 0.1.6(expo@57.0.8)(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
version: 0.1.6(expo@57.0.8)(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
react-native-drawer-layout:
|
react-native-drawer-layout:
|
||||||
specifier: ^4.2.3
|
specifier: ^4.2.3
|
||||||
version: 4.2.3(patch_hash=74f2c043cc22ab87054f219e7c7373a509b779b18bfa79d27e7d051d73355130)(react-native-gesture-handler@2.32.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3))(react-native-reanimated@4.6.0(92d1a74bc123f334ae9968fa1c80814f))(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
version: 4.2.3(patch_hash=2a67e397c87df9fb947b1931c9b00724b802a8dca5d3013617e6155f1ae3188e)(react-native-gesture-handler@3.1.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3))(react-native-reanimated@4.6.0(92d1a74bc123f334ae9968fa1c80814f))(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
react-native-edge-to-edge:
|
react-native-edge-to-edge:
|
||||||
specifier: ^1.8.1
|
specifier: ^1.8.1
|
||||||
version: 1.8.1(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
version: 1.8.1(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
react-native-gesture-handler:
|
react-native-gesture-handler:
|
||||||
specifier: ~2.32.0
|
specifier: ~3.1.0
|
||||||
version: 2.32.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
version: 3.1.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
react-native-keyboard-controller:
|
react-native-keyboard-controller:
|
||||||
specifier: 1.21.9
|
specifier: 1.21.9
|
||||||
version: 1.21.9(patch_hash=ac52bf7502ff3ad34a8594b5e1a916b96bf87a2523b6abc87c31f03607d52271)(react-native-reanimated@4.6.0(92d1a74bc123f334ae9968fa1c80814f))(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
version: 1.21.9(patch_hash=ac52bf7502ff3ad34a8594b5e1a916b96bf87a2523b6abc87c31f03607d52271)(react-native-reanimated@4.6.0(92d1a74bc123f334ae9968fa1c80814f))(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
@@ -715,7 +715,7 @@ importers:
|
|||||||
version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
sonner-native:
|
sonner-native:
|
||||||
specifier: 0.26.4
|
specifier: 0.26.4
|
||||||
version: 0.26.4(a1115538eb9b7f01f00730be61406201)
|
version: 0.26.4(58a7fe7e7df4354448cb52f8cc2a8c5c)
|
||||||
tippy.js:
|
tippy.js:
|
||||||
specifier: ^6.3.7
|
specifier: ^6.3.7
|
||||||
version: 6.3.7
|
version: 6.3.7
|
||||||
@@ -1764,10 +1764,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
'@egjs/hammerjs@2.0.17':
|
|
||||||
resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==}
|
|
||||||
engines: {node: '>=0.8.0'}
|
|
||||||
|
|
||||||
'@emnapi/runtime@1.11.3':
|
'@emnapi/runtime@1.11.3':
|
||||||
resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
|
resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
|
||||||
|
|
||||||
@@ -3990,9 +3986,6 @@ packages:
|
|||||||
'@types/graceful-fs@4.1.9':
|
'@types/graceful-fs@4.1.9':
|
||||||
resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
|
resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
|
||||||
|
|
||||||
'@types/hammerjs@2.0.46':
|
|
||||||
resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==}
|
|
||||||
|
|
||||||
'@types/html-minifier-terser@6.1.0':
|
'@types/html-minifier-terser@6.1.0':
|
||||||
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
|
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
|
||||||
|
|
||||||
@@ -4080,9 +4073,6 @@ packages:
|
|||||||
'@types/react-test-renderer@19.1.0':
|
'@types/react-test-renderer@19.1.0':
|
||||||
resolution: {integrity: sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==}
|
resolution: {integrity: sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==}
|
||||||
|
|
||||||
'@types/react@19.1.17':
|
|
||||||
resolution: {integrity: sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==}
|
|
||||||
|
|
||||||
'@types/react@19.2.18':
|
'@types/react@19.2.18':
|
||||||
resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==}
|
resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==}
|
||||||
|
|
||||||
@@ -6312,9 +6302,6 @@ packages:
|
|||||||
hls.js@1.6.16:
|
hls.js@1.6.16:
|
||||||
resolution: {integrity: sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==}
|
resolution: {integrity: sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==}
|
||||||
|
|
||||||
hoist-non-react-statics@3.3.2:
|
|
||||||
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
|
||||||
|
|
||||||
hosted-git-info@7.0.2:
|
hosted-git-info@7.0.2:
|
||||||
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
|
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
|
||||||
engines: {node: ^16.14.0 || >=18.0.0}
|
engines: {node: ^16.14.0 || >=18.0.0}
|
||||||
@@ -8369,8 +8356,8 @@ packages:
|
|||||||
react: '*'
|
react: '*'
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
|
|
||||||
react-native-gesture-handler@2.32.0:
|
react-native-gesture-handler@3.1.0:
|
||||||
resolution: {integrity: sha512-uYIMOKlKENORq2SABE+jIjbPU+h5I/sQKcq2v16zRq848nwEp1fWRVwML4QWqijc8UcXJC25o54S8GQd4Mf2OA==}
|
resolution: {integrity: sha512-+kWVyZ6vLdtyFa1/aOc/sZncLAVPUKxhji/ttbiLI7hOaSU44bLjhI7p+Ns+pMl2r3RqPXssl5qHReYet9G77g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '*'
|
react: '*'
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
@@ -10964,10 +10951,6 @@ snapshots:
|
|||||||
|
|
||||||
'@discoveryjs/json-ext@0.5.7': {}
|
'@discoveryjs/json-ext@0.5.7': {}
|
||||||
|
|
||||||
'@egjs/hammerjs@2.0.17':
|
|
||||||
dependencies:
|
|
||||||
'@types/hammerjs': 2.0.46
|
|
||||||
|
|
||||||
'@emnapi/runtime@1.11.3':
|
'@emnapi/runtime@1.11.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@@ -13580,8 +13563,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.12.4
|
'@types/node': 24.12.4
|
||||||
|
|
||||||
'@types/hammerjs@2.0.46': {}
|
|
||||||
|
|
||||||
'@types/html-minifier-terser@6.1.0': {}
|
'@types/html-minifier-terser@6.1.0': {}
|
||||||
|
|
||||||
'@types/http-errors@2.0.5': {}
|
'@types/http-errors@2.0.5': {}
|
||||||
@@ -13673,11 +13654,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/react-test-renderer@19.1.0':
|
'@types/react-test-renderer@19.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 19.1.17
|
'@types/react': 19.2.18
|
||||||
|
|
||||||
'@types/react@19.1.17':
|
|
||||||
dependencies:
|
|
||||||
csstype: 3.2.3
|
|
||||||
|
|
||||||
'@types/react@19.2.18':
|
'@types/react@19.2.18':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -16164,10 +16141,6 @@ snapshots:
|
|||||||
|
|
||||||
hls.js@1.6.16: {}
|
hls.js@1.6.16: {}
|
||||||
|
|
||||||
hoist-non-react-statics@3.3.2:
|
|
||||||
dependencies:
|
|
||||||
react-is: 16.13.1
|
|
||||||
|
|
||||||
hosted-git-info@7.0.2:
|
hosted-git-info@7.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache: 10.4.3
|
lru-cache: 10.4.3
|
||||||
@@ -18481,12 +18454,12 @@ snapshots:
|
|||||||
'@babel/runtime': 7.29.2
|
'@babel/runtime': 7.29.2
|
||||||
dotenv: 16.6.1
|
dotenv: 16.6.1
|
||||||
|
|
||||||
? react-native-drawer-layout@4.2.3(patch_hash=74f2c043cc22ab87054f219e7c7373a509b779b18bfa79d27e7d051d73355130)(react-native-gesture-handler@2.32.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3))(react-native-reanimated@4.6.0(92d1a74bc123f334ae9968fa1c80814f))(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
? react-native-drawer-layout@4.2.3(patch_hash=2a67e397c87df9fb947b1931c9b00724b802a8dca5d3013617e6155f1ae3188e)(react-native-gesture-handler@3.1.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3))(react-native-reanimated@4.6.0(92d1a74bc123f334ae9968fa1c80814f))(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
: dependencies:
|
: dependencies:
|
||||||
color: 4.2.3
|
color: 4.2.3
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
||||||
react-native-gesture-handler: 2.32.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
react-native-gesture-handler: 3.1.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
react-native-reanimated: 4.6.0(92d1a74bc123f334ae9968fa1c80814f)
|
react-native-reanimated: 4.6.0(92d1a74bc123f334ae9968fa1c80814f)
|
||||||
use-latest-callback: 0.2.6(react@19.2.3)
|
use-latest-callback: 0.2.6(react@19.2.3)
|
||||||
|
|
||||||
@@ -18495,11 +18468,9 @@ snapshots:
|
|||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
||||||
|
|
||||||
react-native-gesture-handler@2.32.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3):
|
react-native-gesture-handler@3.1.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@egjs/hammerjs': 2.0.17
|
|
||||||
'@types/react-test-renderer': 19.1.0
|
'@types/react-test-renderer': 19.1.0
|
||||||
hoist-non-react-statics: 3.3.2
|
|
||||||
invariant: 2.2.4
|
invariant: 2.2.4
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
||||||
@@ -19164,11 +19135,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
atomic-sleep: 1.0.0
|
atomic-sleep: 1.0.0
|
||||||
|
|
||||||
sonner-native@0.26.4(a1115538eb9b7f01f00730be61406201):
|
sonner-native@0.26.4(58a7fe7e7df4354448cb52f8cc2a8c5c):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
react-native: 0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1)
|
||||||
react-native-gesture-handler: 2.32.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
react-native-gesture-handler: 3.1.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
react-native-reanimated: 4.6.0(92d1a74bc123f334ae9968fa1c80814f)
|
react-native-reanimated: 4.6.0(92d1a74bc123f334ae9968fa1c80814f)
|
||||||
react-native-safe-area-context: 5.7.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
react-native-safe-area-context: 5.7.0(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
react-native-screens: 4.26.2(patch_hash=ba3295d44434a729f143a6b2c24e4a9b2f911ab200b2bc47e46cdfeaa1536f7c)(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
react-native-screens: 4.26.2(patch_hash=ba3295d44434a729f143a6b2c24e4a9b2f911ab200b2bc47e46cdfeaa1536f7c)(react-native@0.86.0(patch_hash=239208992c380d6785576d1fae2e3f60f60f509d7b09d56bf552be29d6c42a06)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3)
|
||||||
|
|||||||
@@ -20,11 +20,12 @@ import {
|
|||||||
type ViewStyle,
|
type ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {
|
import {
|
||||||
Gesture,
|
|
||||||
GestureDetector,
|
GestureDetector,
|
||||||
type GestureStateChangeEvent,
|
type PanGestureActiveEvent,
|
||||||
type GestureUpdateEvent,
|
useCompetingGestures,
|
||||||
type PanGestureHandlerEventPayload,
|
useExclusiveGestures,
|
||||||
|
usePanGesture,
|
||||||
|
useTapGesture,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import {KeyboardEvents} from 'react-native-keyboard-controller'
|
import {KeyboardEvents} from 'react-native-keyboard-controller'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
@@ -299,24 +300,19 @@ export function Trigger({
|
|||||||
}
|
}
|
||||||
}, [context, insets])
|
}, [context, insets])
|
||||||
|
|
||||||
const tapGesture = useMemo(() => {
|
const tapGesture = useTapGesture({
|
||||||
const gesture = Gesture.Tap()
|
numberOfTaps: 1,
|
||||||
.numberOfTaps(1)
|
cancelsTouchesInView: false,
|
||||||
.cancelsTouchesInView(false)
|
runOnJS: true,
|
||||||
.runOnJS(true)
|
onDeactivate: onTap ? () => void onTap() : undefined,
|
||||||
if (onTap) {
|
})
|
||||||
gesture.onEnd(() => void onTap())
|
|
||||||
}
|
|
||||||
return gesture
|
|
||||||
}, [onTap])
|
|
||||||
|
|
||||||
const doubleTapGesture = useMemo(() => {
|
const doubleTapGesture = useTapGesture({
|
||||||
return Gesture.Tap()
|
numberOfTaps: 2,
|
||||||
.numberOfTaps(2)
|
hitSlop: HITSLOP_10,
|
||||||
.hitSlop(HITSLOP_10)
|
runOnJS: true,
|
||||||
.onEnd(() => void open('auxiliary-only'))
|
onDeactivate: () => void open('auxiliary-only'),
|
||||||
.runOnJS(true)
|
})
|
||||||
}, [open])
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
hoverablesSV,
|
hoverablesSV,
|
||||||
@@ -336,34 +332,33 @@ export function Trigger({
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const pressAndHoldGesture = useMemo(() => {
|
const pressAndHoldGesture = usePanGesture({
|
||||||
return Gesture.Pan()
|
activateAfterLongPress: 500,
|
||||||
.activateAfterLongPress(500)
|
cancelsTouchesInView: false,
|
||||||
.cancelsTouchesInView(false)
|
averageTouches: true,
|
||||||
.averageTouches(true)
|
onActivate: () => {
|
||||||
.onStart(() => {
|
'worklet'
|
||||||
'worklet'
|
scheduleOnRN(open, 'full')
|
||||||
scheduleOnRN(open, 'full')
|
},
|
||||||
})
|
onUpdate: evt => {
|
||||||
.onUpdate(evt => {
|
'worklet'
|
||||||
'worklet'
|
const item = getHoveredHoverable(evt, hoverablesSV, translationSV)
|
||||||
const item = getHoveredHoverable(evt, hoverablesSV, translationSV)
|
hoveredItemSV.set(item)
|
||||||
hoveredItemSV.set(item)
|
},
|
||||||
})
|
onDeactivate: () => {
|
||||||
.onEnd(() => {
|
'worklet'
|
||||||
'worklet'
|
// don't recalculate hovered item - if they haven't moved their finger from
|
||||||
// don't recalculate hovered item - if they haven't moved their finger from
|
// the initial press, it's jarring to then select the item underneath
|
||||||
// the initial press, it's jarring to then select the item underneath
|
// as the menu may have slid into place beneath their finger
|
||||||
// as the menu may have slid into place beneath their finger
|
const item = hoveredItemSV.get()
|
||||||
const item = hoveredItemSV.get()
|
if (item) {
|
||||||
if (item) {
|
scheduleOnRN(onTouchUpMenuItem, item)
|
||||||
scheduleOnRN(onTouchUpMenuItem, item)
|
}
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}, [open, hoverablesSV, onTouchUpMenuItem, hoveredItemSV, translationSV])
|
|
||||||
|
|
||||||
// Order matters here: doubleTapGesture must come before tapGesture.
|
// Order matters here: doubleTapGesture must come before tapGesture.
|
||||||
const tapAndHoldGestures = Gesture.Exclusive(
|
const tapAndHoldGestures = useExclusiveGestures(
|
||||||
doubleTapGesture,
|
doubleTapGesture,
|
||||||
tapGesture,
|
tapGesture,
|
||||||
pressAndHoldGesture,
|
pressAndHoldGesture,
|
||||||
@@ -371,11 +366,13 @@ export function Trigger({
|
|||||||
|
|
||||||
// An optional swipe gesture (e.g. swipe-to-reply) races against the tap/hold
|
// An optional swipe gesture (e.g. swipe-to-reply) races against the tap/hold
|
||||||
// group: whichever activates first wins and cancels the rest, so they're
|
// group: whichever activates first wins and cancels the rest, so they're
|
||||||
// mutually exclusive. Race (not Exclusive) avoids a held-but-not-yet-moved
|
// mutually exclusive. Competing (not Exclusive) avoids a held-but-not-yet-moved
|
||||||
// swipe Pan blocking the long-press from firing.
|
// swipe Pan blocking the long-press from firing.
|
||||||
const composedGestures = swipeGesture
|
const composedGestures = useCompetingGestures(
|
||||||
? Gesture.Race(swipeGesture, tapAndHoldGestures)
|
...(swipeGesture
|
||||||
: tapAndHoldGestures
|
? [swipeGesture, tapAndHoldGestures]
|
||||||
|
: [tapAndHoldGestures]),
|
||||||
|
)
|
||||||
|
|
||||||
const measurement = context.measurement || pendingMeasurement?.measurement
|
const measurement = context.measurement || pendingMeasurement?.measurement
|
||||||
|
|
||||||
@@ -990,9 +987,7 @@ function measureView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getHoveredHoverable(
|
function getHoveredHoverable(
|
||||||
evt:
|
evt: PanGestureActiveEvent,
|
||||||
| GestureStateChangeEvent<PanGestureHandlerEventPayload>
|
|
||||||
| GestureUpdateEvent<PanGestureHandlerEventPayload>,
|
|
||||||
hoverables: SharedValue<Record<string, {id: string; rect: Measurement}>>,
|
hoverables: SharedValue<Record<string, {id: string; rect: Measurement}>>,
|
||||||
translation: SharedValue<number>,
|
translation: SharedValue<number>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
type StyleProp,
|
type StyleProp,
|
||||||
type ViewStyle,
|
type ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {type GestureType} from 'react-native-gesture-handler'
|
import {type PanGesture} from 'react-native-gesture-handler'
|
||||||
import {type SharedValue} from 'react-native-reanimated'
|
import {type SharedValue} from 'react-native-reanimated'
|
||||||
|
|
||||||
import type * as Dialog from '#/components/Dialog'
|
import type * as Dialog from '#/components/Dialog'
|
||||||
@@ -89,7 +89,7 @@ export type TriggerProps = {
|
|||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
/**
|
/**
|
||||||
* Callback for single taps. Composed with the double-tap and
|
* Callback for single taps. Composed with the double-tap and
|
||||||
* press-and-hold gestures via `Gesture.Exclusive`, so a double tap
|
* press-and-hold gestures via `useExclusiveGestures`, so a double tap
|
||||||
* does not also fire this handler.
|
* does not also fire this handler.
|
||||||
*
|
*
|
||||||
* @platform ios, android
|
* @platform ios, android
|
||||||
@@ -97,12 +97,13 @@ export type TriggerProps = {
|
|||||||
onTap?: () => void
|
onTap?: () => void
|
||||||
/**
|
/**
|
||||||
* An optional gesture (e.g. swipe-to-reply) composed into the same
|
* An optional gesture (e.g. swipe-to-reply) composed into the same
|
||||||
* arbitration group as the tap and press-and-hold gestures via `Gesture.Race`,
|
* arbitration group as the tap and press-and-hold gestures via
|
||||||
* making it mutually exclusive with them - only one can win a given touch.
|
* `useCompetingGestures`, making it mutually exclusive with them - only one
|
||||||
|
* can win a given touch.
|
||||||
*
|
*
|
||||||
* @platform ios, android
|
* @platform ios, android
|
||||||
*/
|
*/
|
||||||
swipeGesture?: GestureType
|
swipeGesture?: PanGesture
|
||||||
}
|
}
|
||||||
export type TriggerChildProps =
|
export type TriggerChildProps =
|
||||||
| {
|
| {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {useLayoutEffect, useRef} from 'react'
|
import {useLayoutEffect, useRef} from 'react'
|
||||||
import {Gesture, GestureDetector} from 'react-native-gesture-handler'
|
import {GestureDetector, usePanGesture} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
type AnimatedRef,
|
type AnimatedRef,
|
||||||
measure,
|
measure,
|
||||||
@@ -253,8 +253,8 @@ function SortableItem<T>({
|
|||||||
|
|
||||||
const lastHapticSlot = useSharedValue(-1)
|
const lastHapticSlot = useSharedValue(-1)
|
||||||
|
|
||||||
const gesture = Gesture.Pan()
|
const gesture = usePanGesture({
|
||||||
.onStart(() => {
|
onActivate: () => {
|
||||||
'worklet'
|
'worklet'
|
||||||
const s = state.get()
|
const s = state.get()
|
||||||
const mySlot = s.slots[itemKey]
|
const mySlot = s.slots[itemKey]
|
||||||
@@ -268,8 +268,8 @@ function SortableItem<T>({
|
|||||||
scheduleOnRN(onDragStart)
|
scheduleOnRN(onDragStart)
|
||||||
}
|
}
|
||||||
scheduleOnRN(playHaptic)
|
scheduleOnRN(playHaptic)
|
||||||
})
|
},
|
||||||
.onChange(e => {
|
onUpdate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
const startSlot = state.get().dragStartSlot
|
const startSlot = state.get().dragStartSlot
|
||||||
const minY = -startSlot * itemHeight
|
const minY = -startSlot * itemHeight
|
||||||
@@ -287,8 +287,8 @@ function SortableItem<T>({
|
|||||||
lastHapticSlot.set(clampedSlot)
|
lastHapticSlot.set(clampedSlot)
|
||||||
scheduleOnRN(playHaptic, 'Light')
|
scheduleOnRN(playHaptic, 'Light')
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
.onEnd(() => {
|
onDeactivate: () => {
|
||||||
'worklet'
|
'worklet'
|
||||||
// Stop auto-scroll BEFORE the snap animation.
|
// Stop auto-scroll BEFORE the snap animation.
|
||||||
isGestureActive.set(false)
|
isGestureActive.set(false)
|
||||||
@@ -338,9 +338,9 @@ function SortableItem<T>({
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
// Reset if the gesture is cancelled without onEnd firing.
|
// Reset if the gesture is cancelled without onDeactivate firing.
|
||||||
.onFinalize(() => {
|
onFinalize: () => {
|
||||||
'worklet'
|
'worklet'
|
||||||
isGestureActive.set(false)
|
isGestureActive.set(false)
|
||||||
if (state.get().activeKey === itemKey && dragY.get() === 0) {
|
if (state.get().activeKey === itemKey && dragY.get() === 0) {
|
||||||
@@ -350,7 +350,8 @@ function SortableItem<T>({
|
|||||||
scheduleOnRN(onDragEnd)
|
scheduleOnRN(onDragEnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
|
||||||
// All vertical positioning is via translateY (no `top`). This avoids
|
// All vertical positioning is via translateY (no `top`). This avoids
|
||||||
// discrete jumps when slots change — Reanimated smoothly animates from
|
// discrete jumps when slots change — Reanimated smoothly animates from
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import {memo, useState} from 'react'
|
import {memo, useState} from 'react'
|
||||||
import {ActivityIndicator, StyleSheet} from 'react-native'
|
import {ActivityIndicator, StyleSheet} from 'react-native'
|
||||||
import {
|
import {
|
||||||
Gesture,
|
|
||||||
GestureDetector,
|
GestureDetector,
|
||||||
type PanGesture,
|
type PanGesture,
|
||||||
|
useExclusiveGestures,
|
||||||
|
useManualGesture,
|
||||||
|
usePanGesture,
|
||||||
|
usePinchGesture,
|
||||||
|
useSimultaneousGestures,
|
||||||
|
useTapGesture,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
type AnimatableValue,
|
type AnimatableValue,
|
||||||
@@ -137,16 +142,16 @@ const ImageItem = ({
|
|||||||
return [dx, dy]
|
return [dx, dy]
|
||||||
}
|
}
|
||||||
|
|
||||||
const pinch = Gesture.Pinch()
|
const pinch = usePinchGesture({
|
||||||
.onStart(e => {
|
onActivate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
const screenSize = measureSafeArea()
|
const screenSize = measureSafeArea()
|
||||||
pinchOrigin.set({
|
pinchOrigin.set({
|
||||||
x: e.focalX - screenSize.width / 2,
|
x: e.focalX - screenSize.width / 2,
|
||||||
y: e.focalY - screenSize.height / 2,
|
y: e.focalY - screenSize.height / 2,
|
||||||
})
|
})
|
||||||
})
|
},
|
||||||
.onChange(e => {
|
onUpdate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
const screenSize = measureSafeArea()
|
const screenSize = measureSafeArea()
|
||||||
if (!imageDimensions) {
|
if (!imageDimensions) {
|
||||||
@@ -181,8 +186,8 @@ const ImageItem = ({
|
|||||||
y: pt.y + dy,
|
y: pt.y + dy,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
.onEnd(() => {
|
onDeactivate: () => {
|
||||||
'worklet'
|
'worklet'
|
||||||
// Commit just the pinch.
|
// Commit just the pinch.
|
||||||
let t = createTransform()
|
let t = createTransform()
|
||||||
@@ -200,13 +205,14 @@ const ImageItem = ({
|
|||||||
pinchScale.set(1)
|
pinchScale.set(1)
|
||||||
pinchOrigin.set({x: 0, y: 0})
|
pinchOrigin.set({x: 0, y: 0})
|
||||||
pinchTranslation.set({x: 0, y: 0})
|
pinchTranslation.set({x: 0, y: 0})
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const pan = Gesture.Pan()
|
const pan = usePanGesture({
|
||||||
.averageTouches(true)
|
averageTouches: true,
|
||||||
// Unlike .enabled(isScaled), this ensures that an initial pinch can turn into a pan midway:
|
// Unlike enabled: isScaled, this ensures that an initial pinch can turn into a pan midway:
|
||||||
.minPointers(isScaled ? 1 : 2)
|
minPointers: isScaled ? 1 : 2,
|
||||||
.onChange(e => {
|
onUpdate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
const screenSize = measureSafeArea()
|
const screenSize = measureSafeArea()
|
||||||
if (!imageDimensions) {
|
if (!imageDimensions) {
|
||||||
@@ -229,8 +235,8 @@ const ImageItem = ({
|
|||||||
nextPanTranslation.x += dx
|
nextPanTranslation.x += dx
|
||||||
nextPanTranslation.y += dy
|
nextPanTranslation.y += dy
|
||||||
panTranslation.set(nextPanTranslation)
|
panTranslation.set(nextPanTranslation)
|
||||||
})
|
},
|
||||||
.onEnd(() => {
|
onDeactivate: () => {
|
||||||
'worklet'
|
'worklet'
|
||||||
// Commit just the pan.
|
// Commit just the pan.
|
||||||
let t = createTransform()
|
let t = createTransform()
|
||||||
@@ -241,16 +247,19 @@ const ImageItem = ({
|
|||||||
|
|
||||||
// Reset just the pan.
|
// Reset just the pan.
|
||||||
panTranslation.set({x: 0, y: 0})
|
panTranslation.set({x: 0, y: 0})
|
||||||
})
|
},
|
||||||
|
|
||||||
const singleTap = Gesture.Tap().onEnd(() => {
|
|
||||||
'worklet'
|
|
||||||
scheduleOnRN(onTap)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const doubleTap = Gesture.Tap()
|
const singleTap = useTapGesture({
|
||||||
.numberOfTaps(2)
|
onDeactivate: () => {
|
||||||
.onEnd(e => {
|
'worklet'
|
||||||
|
scheduleOnRN(onTap)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const doubleTap = useTapGesture({
|
||||||
|
numberOfTaps: 2,
|
||||||
|
onDeactivate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
const screenSize = measureSafeArea()
|
const screenSize = measureSafeArea()
|
||||||
if (!imageDimensions || !imageAspect) {
|
if (!imageDimensions || !imageAspect) {
|
||||||
@@ -295,17 +304,21 @@ const ImageItem = ({
|
|||||||
const finalTransform = createTransform()
|
const finalTransform = createTransform()
|
||||||
prependPinch(finalTransform, scale, origin, {x: dx, y: dy})
|
prependPinch(finalTransform, scale, origin, {x: dx, y: dy})
|
||||||
committedTransform.set(withClampedSpring(finalTransform))
|
committedTransform.set(withClampedSpring(finalTransform))
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// If the parent is not at rest, provide a no-op gesture.
|
||||||
|
const noopGesture = useManualGesture()
|
||||||
|
const pinchAndPan = useSimultaneousGestures(pinch, pan)
|
||||||
|
const exclusiveGesture = useExclusiveGestures(
|
||||||
|
dismissSwipePan,
|
||||||
|
pinchAndPan,
|
||||||
|
doubleTap,
|
||||||
|
singleTap,
|
||||||
|
)
|
||||||
const composedGesture = isScrollViewBeingDragged
|
const composedGesture = isScrollViewBeingDragged
|
||||||
? // If the parent is not at rest, provide a no-op gesture.
|
? noopGesture
|
||||||
Gesture.Manual()
|
: exclusiveGesture
|
||||||
: Gesture.Exclusive(
|
|
||||||
dismissSwipePan,
|
|
||||||
Gesture.Simultaneous(pinch, pan),
|
|
||||||
doubleTap,
|
|
||||||
singleTap,
|
|
||||||
)
|
|
||||||
|
|
||||||
const containerStyle = useAnimatedStyle(() => {
|
const containerStyle = useAnimatedStyle(() => {
|
||||||
const {scaleAndMoveTransform, isHidden} = transforms.get()
|
const {scaleAndMoveTransform, isHidden} = transforms.get()
|
||||||
|
|||||||
@@ -9,9 +9,10 @@
|
|||||||
import {memo, useState} from 'react'
|
import {memo, useState} from 'react'
|
||||||
import {ActivityIndicator, StyleSheet} from 'react-native'
|
import {ActivityIndicator, StyleSheet} from 'react-native'
|
||||||
import {
|
import {
|
||||||
Gesture,
|
|
||||||
GestureDetector,
|
GestureDetector,
|
||||||
type PanGesture,
|
type PanGesture,
|
||||||
|
useExclusiveGestures,
|
||||||
|
useTapGesture,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
type SharedValue,
|
type SharedValue,
|
||||||
@@ -115,14 +116,16 @@ const ImageItem = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const singleTap = Gesture.Tap().onEnd(() => {
|
const singleTap = useTapGesture({
|
||||||
'worklet'
|
onDeactivate: () => {
|
||||||
scheduleOnRN(onTap)
|
'worklet'
|
||||||
|
scheduleOnRN(onTap)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const doubleTap = Gesture.Tap()
|
const doubleTap = useTapGesture({
|
||||||
.numberOfTaps(2)
|
numberOfTaps: 2,
|
||||||
.onEnd(e => {
|
onDeactivate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
const screenSize = measureSafeArea()
|
const screenSize = measureSafeArea()
|
||||||
const {absoluteX, absoluteY} = e
|
const {absoluteX, absoluteY} = e
|
||||||
@@ -142,9 +145,10 @@ const ImageItem = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
scheduleOnRN(zoomTo, nextZoomRect)
|
scheduleOnRN(zoomTo, nextZoomRect)
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const composedGesture = Gesture.Exclusive(
|
const composedGesture = useExclusiveGestures(
|
||||||
dismissSwipePan,
|
dismissSwipePan,
|
||||||
doubleTap,
|
doubleTap,
|
||||||
singleTap,
|
singleTap,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
import {useCallback, useEffect, useMemo, useState} from 'react'
|
import {useCallback, useEffect, useMemo, useState} from 'react'
|
||||||
import {PixelRatio, StyleSheet, useWindowDimensions, View} from 'react-native'
|
import {PixelRatio, StyleSheet, useWindowDimensions, View} from 'react-native'
|
||||||
import {SystemBars} from 'react-native-edge-to-edge'
|
import {SystemBars} from 'react-native-edge-to-edge'
|
||||||
import {Gesture} from 'react-native-gesture-handler'
|
import {usePanGesture} from 'react-native-gesture-handler'
|
||||||
import PagerView, {
|
import PagerView, {
|
||||||
type PagerViewOnPageSelectedEvent,
|
type PagerViewOnPageSelectedEvent,
|
||||||
type PageScrollStateChangedNativeEvent,
|
type PageScrollStateChangedNativeEvent,
|
||||||
@@ -566,19 +566,19 @@ function LightboxImage({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const dismissSwipePan = Gesture.Pan()
|
const dismissSwipePan = usePanGesture({
|
||||||
.enabled(isActive && !isScaled)
|
enabled: isActive && !isScaled,
|
||||||
.activeOffsetY([-10, 10])
|
activeOffsetY: [-10, 10],
|
||||||
.failOffsetX([-10, 10])
|
failOffsetX: [-10, 10],
|
||||||
.maxPointers(1)
|
maxPointers: 1,
|
||||||
.onUpdate(e => {
|
onUpdate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
if (openProgress.get() !== 1 || isFlyingAway.get()) {
|
if (openProgress.get() !== 1 || isFlyingAway.get()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dismissSwipeTranslateY.set(e.translationY)
|
dismissSwipeTranslateY.set(e.translationY)
|
||||||
})
|
},
|
||||||
.onEnd(e => {
|
onDeactivate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
if (openProgress.get() !== 1 || isFlyingAway.get()) {
|
if (openProgress.get() !== 1 || isFlyingAway.get()) {
|
||||||
return
|
return
|
||||||
@@ -608,7 +608,8 @@ function LightboxImage({
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImageItem
|
<ImageItem
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {memo, useCallback} from 'react'
|
import {memo, useCallback} from 'react'
|
||||||
import {Platform} from 'react-native'
|
import {Platform} from 'react-native'
|
||||||
import {type GestureType} from 'react-native-gesture-handler'
|
import {type PanGesture} from 'react-native-gesture-handler'
|
||||||
import * as Clipboard from 'expo-clipboard'
|
import * as Clipboard from 'expo-clipboard'
|
||||||
import {type ModerationOpts} from '@bsky/sdk/moderation'
|
import {type ModerationOpts} from '@bsky/sdk/moderation'
|
||||||
import {RichText} from '@bsky/sdk/richtext'
|
import {RichText} from '@bsky/sdk/richtext'
|
||||||
@@ -47,7 +47,7 @@ export let MessageContextMenu = ({
|
|||||||
* Native only. A swipe gesture (swipe-to-reply) composed into the trigger's
|
* Native only. A swipe gesture (swipe-to-reply) composed into the trigger's
|
||||||
* gesture group so it's mutually exclusive with the tap and long-press.
|
* gesture group so it's mutually exclusive with the tap and long-press.
|
||||||
*/
|
*/
|
||||||
swipeGesture?: GestureType
|
swipeGesture?: PanGesture
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {t: l, i18n} = useLingui()
|
const {t: l, i18n} = useLingui()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {useMemo} from 'react'
|
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {Gesture, type GestureType} from 'react-native-gesture-handler'
|
import {type PanGesture, usePanGesture} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
clamp,
|
clamp,
|
||||||
interpolate,
|
interpolate,
|
||||||
@@ -52,8 +51,9 @@ function applyResistance(value: number) {
|
|||||||
*
|
*
|
||||||
* The pan gesture is built here but handed to `children` via a render prop so
|
* The pan gesture is built here but handed to `children` via a render prop so
|
||||||
* the consumer can compose it into the message's context-menu gestures with
|
* the consumer can compose it into the message's context-menu gestures with
|
||||||
* `Gesture.Exclusive`. Sharing one arbitration group is what makes the swipe
|
* `useCompetingGestures`. Sharing one arbitration group is what makes the
|
||||||
* and the long-press mutually exclusive - only one can ever win the touch.
|
* swipe and the long-press mutually exclusive - only one can ever win the
|
||||||
|
* touch.
|
||||||
*/
|
*/
|
||||||
export function SwipeToReply({
|
export function SwipeToReply({
|
||||||
isFromSelf,
|
isFromSelf,
|
||||||
@@ -64,7 +64,7 @@ export function SwipeToReply({
|
|||||||
isFromSelf: boolean
|
isFromSelf: boolean
|
||||||
onReply: () => void
|
onReply: () => void
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
children: (swipeGesture: GestureType) => React.ReactNode
|
children: (swipeGesture: PanGesture) => React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const playHaptic = useHaptics()
|
const playHaptic = useHaptics()
|
||||||
@@ -74,73 +74,56 @@ export function SwipeToReply({
|
|||||||
const hit = useSharedValue(false)
|
const hit = useSharedValue(false)
|
||||||
const iconScale = useSharedValue(1)
|
const iconScale = useSharedValue(1)
|
||||||
|
|
||||||
const swipeGesture = useMemo(() => {
|
const runPop = () => {
|
||||||
const runPop = () => {
|
'worklet'
|
||||||
'worklet'
|
if (isReducedMotion) return
|
||||||
if (isReducedMotion) return
|
iconScale.set(
|
||||||
iconScale.set(
|
withSequence(
|
||||||
withSequence(
|
withTiming(1.2, {duration: 175}),
|
||||||
withTiming(1.2, {duration: 175}),
|
withTiming(1, {duration: 100}),
|
||||||
withTiming(1, {duration: 100}),
|
),
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
Gesture.Pan()
|
|
||||||
.enabled(enabled)
|
|
||||||
// Arm only on the inward axis; the outward direction is effectively
|
|
||||||
// disabled so the bubble can't be dragged off its own edge.
|
|
||||||
.activeOffsetX(
|
|
||||||
isFromSelf
|
|
||||||
? [-10, EFFECTIVELY_DISABLED_OFFSET]
|
|
||||||
: [-EFFECTIVELY_DISABLED_OFFSET, 10],
|
|
||||||
)
|
|
||||||
.activeOffsetY([
|
|
||||||
-EFFECTIVELY_DISABLED_OFFSET,
|
|
||||||
EFFECTIVELY_DISABLED_OFFSET,
|
|
||||||
])
|
|
||||||
.onChange(e => {
|
|
||||||
'worklet'
|
|
||||||
const dir = isFromSelf
|
|
||||||
? Math.min(e.translationX, 0)
|
|
||||||
: Math.max(e.translationX, 0)
|
|
||||||
transX.set(applyResistance(dir))
|
|
||||||
|
|
||||||
const pastThreshold = Math.abs(transX.get()) >= ACTIVATION_THRESHOLD
|
|
||||||
if (pastThreshold && !hit.get()) {
|
|
||||||
hit.set(true)
|
|
||||||
runPop()
|
|
||||||
scheduleOnRN(playHaptic, 'Medium')
|
|
||||||
} else if (!pastThreshold && hit.get()) {
|
|
||||||
hit.set(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.onEnd(() => {
|
|
||||||
'worklet'
|
|
||||||
// Only a clean end (finger lifted past threshold) triggers the reply.
|
|
||||||
if (hit.get()) {
|
|
||||||
scheduleOnRN(onReply)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.onFinalize(() => {
|
|
||||||
'worklet'
|
|
||||||
// Runs on both end and cancellation, so the bubble always animates
|
|
||||||
// home even if the gesture is interrupted mid-swipe.
|
|
||||||
transX.set(withTiming(0, {duration: 200}))
|
|
||||||
hit.set(false)
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
}, [
|
}
|
||||||
isFromSelf,
|
|
||||||
|
const swipeGesture = usePanGesture({
|
||||||
enabled,
|
enabled,
|
||||||
onReply,
|
// Arm only on the inward axis; the outward direction is effectively
|
||||||
playHaptic,
|
// disabled so the bubble can't be dragged off its own edge.
|
||||||
isReducedMotion,
|
activeOffsetX: isFromSelf
|
||||||
transX,
|
? [-10, EFFECTIVELY_DISABLED_OFFSET]
|
||||||
hit,
|
: [-EFFECTIVELY_DISABLED_OFFSET, 10],
|
||||||
iconScale,
|
activeOffsetY: [-EFFECTIVELY_DISABLED_OFFSET, EFFECTIVELY_DISABLED_OFFSET],
|
||||||
])
|
onUpdate: e => {
|
||||||
|
'worklet'
|
||||||
|
const dir = isFromSelf
|
||||||
|
? Math.min(e.translationX, 0)
|
||||||
|
: Math.max(e.translationX, 0)
|
||||||
|
transX.set(applyResistance(dir))
|
||||||
|
|
||||||
|
const pastThreshold = Math.abs(transX.get()) >= ACTIVATION_THRESHOLD
|
||||||
|
if (pastThreshold && !hit.get()) {
|
||||||
|
hit.set(true)
|
||||||
|
runPop()
|
||||||
|
scheduleOnRN(playHaptic, 'Medium')
|
||||||
|
} else if (!pastThreshold && hit.get()) {
|
||||||
|
hit.set(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDeactivate: () => {
|
||||||
|
'worklet'
|
||||||
|
// Only a clean end (finger lifted past threshold) triggers the reply.
|
||||||
|
if (hit.get()) {
|
||||||
|
scheduleOnRN(onReply)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFinalize: () => {
|
||||||
|
'worklet'
|
||||||
|
// Runs on both end and cancellation, so the bubble always animates
|
||||||
|
// home even if the gesture is interrupted mid-swipe.
|
||||||
|
transX.set(withTiming(0, {duration: 200}))
|
||||||
|
hit.set(false)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const contentStyle = useAnimatedStyle(() => ({
|
const contentStyle = useAnimatedStyle(() => ({
|
||||||
transform: [{translateX: transX.get()}],
|
transform: [{translateX: transX.get()}],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {useMemo, useState} from 'react'
|
import {useMemo, useState} from 'react'
|
||||||
import {type ColorValue, Dimensions, View} from 'react-native'
|
import {type ColorValue, Dimensions, View} from 'react-native'
|
||||||
import {Gesture, GestureDetector} from 'react-native-gesture-handler'
|
import {GestureDetector, usePanGesture} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
clamp,
|
clamp,
|
||||||
interpolate,
|
interpolate,
|
||||||
@@ -106,17 +106,17 @@ export function GestureActionView({
|
|||||||
// Absurdly high value so it doesn't interfere with the pan gestures above (i.e., scroll)
|
// Absurdly high value so it doesn't interfere with the pan gestures above (i.e., scroll)
|
||||||
// reanimated doesn't offer great support for disabling y/x axes :/
|
// reanimated doesn't offer great support for disabling y/x axes :/
|
||||||
const effectivelyDisabledOffset = 200
|
const effectivelyDisabledOffset = 200
|
||||||
const panGesture = Gesture.Pan()
|
const panGesture = usePanGesture({
|
||||||
.activeOffsetX([
|
activeOffsetX: [
|
||||||
actions.leftFirst ? -10 : -effectivelyDisabledOffset,
|
actions.leftFirst ? -10 : -effectivelyDisabledOffset,
|
||||||
actions.rightFirst ? 10 : effectivelyDisabledOffset,
|
actions.rightFirst ? 10 : effectivelyDisabledOffset,
|
||||||
])
|
],
|
||||||
.activeOffsetY([-effectivelyDisabledOffset, effectivelyDisabledOffset])
|
activeOffsetY: [-effectivelyDisabledOffset, effectivelyDisabledOffset],
|
||||||
.onStart(() => {
|
onActivate: () => {
|
||||||
'worklet'
|
'worklet'
|
||||||
isActive.set(true)
|
isActive.set(true)
|
||||||
})
|
},
|
||||||
.onChange(e => {
|
onUpdate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
transX.set(e.translationX)
|
transX.set(e.translationX)
|
||||||
|
|
||||||
@@ -189,8 +189,8 @@ export function GestureActionView({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
.onEnd(e => {
|
onDeactivate: e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
if (e.translationX < 0) {
|
if (e.translationX < 0) {
|
||||||
if (hitSecond.get() && actions.leftSecond) {
|
if (hitSecond.get() && actions.leftSecond) {
|
||||||
@@ -209,9 +209,8 @@ export function GestureActionView({
|
|||||||
hitFirst.set(false)
|
hitFirst.set(false)
|
||||||
hitSecond.set(false)
|
hitSecond.set(false)
|
||||||
isActive.set(false)
|
isActive.set(false)
|
||||||
})
|
},
|
||||||
|
})
|
||||||
const composedGesture = Gesture.Simultaneous(panGesture)
|
|
||||||
|
|
||||||
const animatedSliderStyle = useAnimatedStyle(() => {
|
const animatedSliderStyle = useAnimatedStyle(() => {
|
||||||
return {
|
return {
|
||||||
@@ -286,7 +285,7 @@ export function GestureActionView({
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GestureDetector gesture={composedGesture}>
|
<GestureDetector gesture={panGesture}>
|
||||||
<View>
|
<View>
|
||||||
<Animated.View style={[a.absolute, a.inset_0, animatedBackgroundStyle]}>
|
<Animated.View style={[a.absolute, a.inset_0, animatedBackgroundStyle]}>
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {useCallback, useMemo, useState} from 'react'
|
import {useCallback, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {
|
import {
|
||||||
Gesture,
|
|
||||||
GestureDetector,
|
GestureDetector,
|
||||||
type NativeGesture,
|
type NativeGesture,
|
||||||
|
usePanGesture,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
clamp,
|
clamp,
|
||||||
@@ -85,48 +85,38 @@ export function Scrubber({
|
|||||||
[player, isSeekingSV, seekingAnimationSV],
|
[player, isSeekingSV, seekingAnimationSV],
|
||||||
)
|
)
|
||||||
|
|
||||||
const scrubPanGesture = useMemo(() => {
|
const scrubPanGesture = usePanGesture({
|
||||||
return Gesture.Pan()
|
block: scrollGesture,
|
||||||
.blocksExternalGesture(scrollGesture)
|
activeOffsetX: [-10, 10],
|
||||||
.activeOffsetX([-10, 10])
|
failOffsetY: [-10, 10],
|
||||||
.failOffsetY([-10, 10])
|
onActivate: () => {
|
||||||
.onStart(() => {
|
'worklet'
|
||||||
'worklet'
|
seekProgressSV.set(currentTimeSV.get())
|
||||||
seekProgressSV.set(currentTimeSV.get())
|
isSeekingSV.set(true)
|
||||||
isSeekingSV.set(true)
|
seekingAnimationSV.set(withTiming(1, {duration: 500}))
|
||||||
seekingAnimationSV.set(withTiming(1, {duration: 500}))
|
},
|
||||||
})
|
onUpdate: evt => {
|
||||||
.onUpdate(evt => {
|
'worklet'
|
||||||
'worklet'
|
const progress = evt.x / screenWidth
|
||||||
const progress = evt.x / screenWidth
|
seekProgressSV.set(
|
||||||
seekProgressSV.set(
|
clamp(progress * durationSV.get(), 0, durationSV.get()),
|
||||||
clamp(progress * durationSV.get(), 0, durationSV.get()),
|
)
|
||||||
)
|
},
|
||||||
})
|
onDeactivate: evt => {
|
||||||
.onEnd(evt => {
|
'worklet'
|
||||||
'worklet'
|
isSeekingSV.get()
|
||||||
isSeekingSV.get()
|
|
||||||
|
|
||||||
const progress = evt.x / screenWidth
|
const progress = evt.x / screenWidth
|
||||||
const newTime = clamp(progress * durationSV.get(), 0, durationSV.get())
|
const newTime = clamp(progress * durationSV.get(), 0, durationSV.get())
|
||||||
|
|
||||||
// optimisically set the progress bar
|
// optimisically set the progress bar
|
||||||
seekProgressSV.set(newTime)
|
seekProgressSV.set(newTime)
|
||||||
|
|
||||||
// it's seek by, so offset by the current time
|
// it's seek by, so offset by the current time
|
||||||
// seekBy sets isSeekingSV back to false, so no need to do that here
|
// seekBy sets isSeekingSV back to false, so no need to do that here
|
||||||
scheduleOnRN(seekBy, newTime - currentTimeSV.get())
|
scheduleOnRN(seekBy, newTime - currentTimeSV.get())
|
||||||
})
|
},
|
||||||
}, [
|
})
|
||||||
scrollGesture,
|
|
||||||
seekingAnimationSV,
|
|
||||||
seekBy,
|
|
||||||
screenWidth,
|
|
||||||
currentTimeSV,
|
|
||||||
durationSV,
|
|
||||||
isSeekingSV,
|
|
||||||
seekProgressSV,
|
|
||||||
])
|
|
||||||
|
|
||||||
const timeStyle = useAnimatedStyle(() => {
|
const timeStyle = useAnimatedStyle(() => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import {
|
|||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {
|
import {
|
||||||
Gesture,
|
|
||||||
GestureDetector,
|
GestureDetector,
|
||||||
type NativeGesture,
|
type NativeGesture,
|
||||||
|
useNativeGesture,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
useAnimatedStyle,
|
useAnimatedStyle,
|
||||||
@@ -258,7 +258,7 @@ function Feed() {
|
|||||||
|
|
||||||
const [currentIndex, setCurrentIndex] = useState(0)
|
const [currentIndex, setCurrentIndex] = useState(0)
|
||||||
|
|
||||||
const scrollGesture = useMemo(() => Gesture.Native(), [])
|
const scrollGesture = useNativeGesture()
|
||||||
|
|
||||||
const renderItem: ListRenderItem<VideoItem> = useCallback(
|
const renderItem: ListRenderItem<VideoItem> = useCallback(
|
||||||
({item, index}) => {
|
({item, index}) => {
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import {createContext, useContext, useMemo, useRef, useState} from 'react'
|
import {createContext, useContext, useMemo, useRef, useState} from 'react'
|
||||||
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||||
import {
|
import {
|
||||||
Gesture,
|
|
||||||
GestureDetector,
|
GestureDetector,
|
||||||
type GestureStateChangeEvent,
|
type PanGestureActiveEvent,
|
||||||
type GestureUpdateEvent,
|
type PanGestureEvent,
|
||||||
type PanGestureHandlerEventPayload,
|
usePanGesture,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import {EventEmitter} from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
export type GlobalGestureEvents = {
|
export type GlobalGestureEvents = {
|
||||||
begin: GestureStateChangeEvent<PanGestureHandlerEventPayload>
|
begin: PanGestureEvent
|
||||||
update: GestureUpdateEvent<PanGestureHandlerEventPayload>
|
update: PanGestureActiveEvent
|
||||||
end: GestureStateChangeEvent<PanGestureHandlerEventPayload>
|
end: PanGestureActiveEvent & {canceled: boolean}
|
||||||
finalize: GestureStateChangeEvent<PanGestureHandlerEventPayload>
|
finalize: PanGestureEvent & {canceled: boolean}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Context = createContext<{
|
const Context = createContext<{
|
||||||
@@ -55,22 +54,22 @@ export function GlobalGestureEventsProvider({
|
|||||||
}),
|
}),
|
||||||
[events, setEnabled],
|
[events, setEnabled],
|
||||||
)
|
)
|
||||||
const gesture = Gesture.Pan()
|
const gesture = usePanGesture({
|
||||||
.runOnJS(true)
|
runOnJS: true,
|
||||||
.enabled(enabled)
|
enabled,
|
||||||
.simultaneousWithExternalGesture()
|
onBegin: e => {
|
||||||
.onBegin(e => {
|
|
||||||
events.emit('begin', e)
|
events.emit('begin', e)
|
||||||
})
|
},
|
||||||
.onUpdate(e => {
|
onUpdate: e => {
|
||||||
events.emit('update', e)
|
events.emit('update', e)
|
||||||
})
|
},
|
||||||
.onEnd(e => {
|
onDeactivate: e => {
|
||||||
events.emit('end', e)
|
events.emit('end', e)
|
||||||
})
|
},
|
||||||
.onFinalize(e => {
|
onFinalize: e => {
|
||||||
events.emit('finalize', e)
|
events.emit('finalize', e)
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Context.Provider value={ctx}>
|
<Context.Provider value={ctx}>
|
||||||
|
|||||||
Reference in New Issue
Block a user