mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-12 22:51:18 +08:00
feat: initial implementation of a flipper plugin
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@ web-report/
|
||||
|
||||
xcuserdata
|
||||
generated
|
||||
dist
|
||||
lib
|
||||
build
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ target 'ReactNavigation' do
|
||||
#
|
||||
# Note that if you have use_frameworks! enabled, Flipper will not work.
|
||||
#
|
||||
use_flipper!
|
||||
post_install do |installer|
|
||||
flipper_post_install(installer)
|
||||
end
|
||||
use_flipper!('Flipper' => '0.75.1', 'Flipper-Folly' => '2.5.3', 'Flipper-RSocket' => '1.3.1')
|
||||
post_install do |installer|
|
||||
flipper_post_install(installer)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
PODS:
|
||||
- boost-for-react-native (1.63.0)
|
||||
- CocoaAsyncSocket (7.6.4)
|
||||
- CocoaLibEvent (1.0.0)
|
||||
- CocoaAsyncSocket (7.6.5)
|
||||
- DoubleConversion (1.1.6)
|
||||
- EXApplication (3.1.0):
|
||||
- EXApplication (3.1.2):
|
||||
- UMCore
|
||||
- EXBlur (9.0.3):
|
||||
- UMCore
|
||||
- EXConstants (10.1.1):
|
||||
- EXConstants (10.1.3):
|
||||
- UMConstantsInterface
|
||||
- UMCore
|
||||
- EXErrorRecovery (2.1.0):
|
||||
- UMCore
|
||||
- EXFileSystem (11.0.0):
|
||||
- EXFileSystem (11.0.2):
|
||||
- UMCore
|
||||
- UMFileSystemInterface
|
||||
- EXFont (9.1.0):
|
||||
@@ -22,7 +21,7 @@ PODS:
|
||||
- React-Core
|
||||
- UMCore
|
||||
- UMImageLoaderInterface
|
||||
- EXKeepAwake (9.1.1):
|
||||
- EXKeepAwake (9.1.2):
|
||||
- UMCore
|
||||
- EXPermissions (12.0.0):
|
||||
- UMCore
|
||||
@@ -32,7 +31,7 @@ PODS:
|
||||
- UMCore
|
||||
- EXStructuredHeaders (1.0.1):
|
||||
- UMCore
|
||||
- EXUpdates (0.5.3):
|
||||
- EXUpdates (0.5.4):
|
||||
- EXStructuredHeaders
|
||||
- React-Core
|
||||
- UMCore
|
||||
@@ -44,50 +43,50 @@ PODS:
|
||||
- React-Core (= 0.63.4)
|
||||
- React-jsi (= 0.63.4)
|
||||
- ReactCommon/turbomodule/core (= 0.63.4)
|
||||
- Flipper (0.54.0):
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- Flipper-RSocket (~> 1.1)
|
||||
- Flipper (0.75.1):
|
||||
- Flipper-Folly (~> 2.5)
|
||||
- Flipper-RSocket (~> 1.3)
|
||||
- Flipper-DoubleConversion (1.1.7)
|
||||
- Flipper-Folly (2.2.0):
|
||||
- Flipper-Folly (2.5.3):
|
||||
- boost-for-react-native
|
||||
- CocoaLibEvent (~> 1.0)
|
||||
- Flipper-DoubleConversion
|
||||
- Flipper-Glog
|
||||
- OpenSSL-Universal (= 1.0.2.19)
|
||||
- libevent (~> 2.1.12)
|
||||
- OpenSSL-Universal (= 1.1.180)
|
||||
- Flipper-Glog (0.3.6)
|
||||
- Flipper-PeerTalk (0.0.4)
|
||||
- Flipper-RSocket (1.1.0):
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- FlipperKit (0.54.0):
|
||||
- FlipperKit/Core (= 0.54.0)
|
||||
- FlipperKit/Core (0.54.0):
|
||||
- Flipper (~> 0.54.0)
|
||||
- Flipper-RSocket (1.3.1):
|
||||
- Flipper-Folly (~> 2.5)
|
||||
- FlipperKit (0.75.1):
|
||||
- FlipperKit/Core (= 0.75.1)
|
||||
- FlipperKit/Core (0.75.1):
|
||||
- Flipper (~> 0.75.1)
|
||||
- FlipperKit/CppBridge
|
||||
- FlipperKit/FBCxxFollyDynamicConvert
|
||||
- FlipperKit/FBDefines
|
||||
- FlipperKit/FKPortForwarding
|
||||
- FlipperKit/CppBridge (0.54.0):
|
||||
- Flipper (~> 0.54.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (0.54.0):
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- FlipperKit/FBDefines (0.54.0)
|
||||
- FlipperKit/FKPortForwarding (0.54.0):
|
||||
- FlipperKit/CppBridge (0.75.1):
|
||||
- Flipper (~> 0.75.1)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (0.75.1):
|
||||
- Flipper-Folly (~> 2.5)
|
||||
- FlipperKit/FBDefines (0.75.1)
|
||||
- FlipperKit/FKPortForwarding (0.75.1):
|
||||
- CocoaAsyncSocket (~> 7.6)
|
||||
- Flipper-PeerTalk (~> 0.0.4)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (0.54.0)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (0.54.0):
|
||||
- FlipperKit/FlipperKitHighlightOverlay (0.75.1)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (0.75.1):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable
|
||||
- YogaKit (~> 1.18)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (0.54.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (0.54.0):
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (0.75.1)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (0.75.1):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitReactPlugin (0.54.0):
|
||||
- FlipperKit/FlipperKitReactPlugin (0.75.1):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0):
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (0.75.1):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/SKIOSNetworkPlugin (0.54.0):
|
||||
- FlipperKit/SKIOSNetworkPlugin (0.75.1):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitNetworkPlugin
|
||||
- Folly (2020.01.13.00):
|
||||
@@ -100,9 +99,8 @@ PODS:
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- OpenSSL-Universal (1.0.2.19):
|
||||
- OpenSSL-Universal/Static (= 1.0.2.19)
|
||||
- OpenSSL-Universal/Static (1.0.2.19)
|
||||
- libevent (2.1.12)
|
||||
- OpenSSL-Universal (1.1.180)
|
||||
- RCTRequired (0.63.4)
|
||||
- RCTTypeSafety (0.63.4):
|
||||
- FBLazyVector (= 0.63.4)
|
||||
@@ -271,6 +269,8 @@ PODS:
|
||||
- React-jsinspector (0.63.4)
|
||||
- react-native-appearance (0.3.4):
|
||||
- React
|
||||
- react-native-flipper (0.80.0):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (3.2.0):
|
||||
- React-Core
|
||||
- react-native-viewpager (5.0.12):
|
||||
@@ -337,7 +337,7 @@ PODS:
|
||||
- React-jsi (= 0.63.4)
|
||||
- RNCAsyncStorage (1.15.1):
|
||||
- React-Core
|
||||
- RNCMaskedView (0.2.3):
|
||||
- RNCMaskedView (0.2.4):
|
||||
- React-Core
|
||||
- RNGestureHandler (1.10.3):
|
||||
- React-Core
|
||||
@@ -388,7 +388,7 @@ PODS:
|
||||
- UMImageLoaderInterface (6.1.0)
|
||||
- UMPermissionsInterface (6.1.0):
|
||||
- UMCore
|
||||
- UMReactNativeAdapter (6.2.1):
|
||||
- UMReactNativeAdapter (6.2.2):
|
||||
- React-Core
|
||||
- UMCore
|
||||
- UMFontInterface
|
||||
@@ -416,25 +416,25 @@ DEPENDENCIES:
|
||||
- EXUpdates (from `../../node_modules/expo-updates/ios`)
|
||||
- FBLazyVector (from `../../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../../node_modules/react-native/Libraries/FBReactNativeSpec`)
|
||||
- Flipper (~> 0.54.0)
|
||||
- Flipper (= 0.75.1)
|
||||
- Flipper-DoubleConversion (= 1.1.7)
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- Flipper-Folly (= 2.5.3)
|
||||
- Flipper-Glog (= 0.3.6)
|
||||
- Flipper-PeerTalk (~> 0.0.4)
|
||||
- Flipper-RSocket (~> 1.1)
|
||||
- FlipperKit (~> 0.54.0)
|
||||
- FlipperKit/Core (~> 0.54.0)
|
||||
- FlipperKit/CppBridge (~> 0.54.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (~> 0.54.0)
|
||||
- FlipperKit/FBDefines (~> 0.54.0)
|
||||
- FlipperKit/FKPortForwarding (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitReactPlugin (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.54.0)
|
||||
- FlipperKit/SKIOSNetworkPlugin (~> 0.54.0)
|
||||
- Flipper-RSocket (= 1.3.1)
|
||||
- FlipperKit (= 0.75.1)
|
||||
- FlipperKit/Core (= 0.75.1)
|
||||
- FlipperKit/CppBridge (= 0.75.1)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (= 0.75.1)
|
||||
- FlipperKit/FBDefines (= 0.75.1)
|
||||
- FlipperKit/FKPortForwarding (= 0.75.1)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (= 0.75.1)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (= 0.75.1)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (= 0.75.1)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (= 0.75.1)
|
||||
- FlipperKit/FlipperKitReactPlugin (= 0.75.1)
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (= 0.75.1)
|
||||
- FlipperKit/SKIOSNetworkPlugin (= 0.75.1)
|
||||
- Folly (from `../../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
||||
- glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- RCTRequired (from `../../node_modules/react-native/Libraries/RCTRequired`)
|
||||
@@ -450,6 +450,7 @@ DEPENDENCIES:
|
||||
- React-jsiexecutor (from `../../node_modules/react-native/ReactCommon/jsiexecutor`)
|
||||
- React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- react-native-appearance (from `../../node_modules/react-native-appearance`)
|
||||
- react-native-flipper (from `../../node_modules/react-native-flipper`)
|
||||
- react-native-safe-area-context (from `../../node_modules/react-native-safe-area-context`)
|
||||
- react-native-viewpager (from `../node_modules/react-native-pager-view`)
|
||||
- React-RCTActionSheet (from `../../node_modules/react-native/Libraries/ActionSheetIOS`)
|
||||
@@ -463,7 +464,7 @@ DEPENDENCIES:
|
||||
- React-RCTVibration (from `../../node_modules/react-native/Libraries/Vibration`)
|
||||
- ReactCommon/turbomodule/core (from `../../node_modules/react-native/ReactCommon`)
|
||||
- "RNCAsyncStorage (from `../../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- "RNCMaskedView (from `../../node_modules/@react-native-masked-view/masked-view`)"
|
||||
- "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
|
||||
- RNGestureHandler (from `../../node_modules/react-native-gesture-handler`)
|
||||
- RNReanimated (from `../../node_modules/react-native-reanimated`)
|
||||
- RNScreens (from `../../node_modules/react-native-screens`)
|
||||
@@ -487,7 +488,6 @@ SPEC REPOS:
|
||||
trunk:
|
||||
- boost-for-react-native
|
||||
- CocoaAsyncSocket
|
||||
- CocoaLibEvent
|
||||
- Flipper
|
||||
- Flipper-DoubleConversion
|
||||
- Flipper-Folly
|
||||
@@ -495,6 +495,7 @@ SPEC REPOS:
|
||||
- Flipper-PeerTalk
|
||||
- Flipper-RSocket
|
||||
- FlipperKit
|
||||
- libevent
|
||||
- OpenSSL-Universal
|
||||
- YogaKit
|
||||
|
||||
@@ -555,6 +556,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../../node_modules/react-native/ReactCommon/jsinspector"
|
||||
react-native-appearance:
|
||||
:path: "../../node_modules/react-native-appearance"
|
||||
react-native-flipper:
|
||||
:path: "../../node_modules/react-native-flipper"
|
||||
react-native-safe-area-context:
|
||||
:path: "../../node_modules/react-native-safe-area-context"
|
||||
react-native-viewpager:
|
||||
@@ -582,7 +585,7 @@ EXTERNAL SOURCES:
|
||||
RNCAsyncStorage:
|
||||
:path: "../../node_modules/@react-native-async-storage/async-storage"
|
||||
RNCMaskedView:
|
||||
:path: "../../node_modules/@react-native-masked-view/masked-view"
|
||||
:path: "../node_modules/@react-native-masked-view/masked-view"
|
||||
RNGestureHandler:
|
||||
:path: "../../node_modules/react-native-gesture-handler"
|
||||
RNReanimated:
|
||||
@@ -622,33 +625,33 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
|
||||
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: cde416483dac037923206447da6e1454df403714
|
||||
EXApplication: fe13d11e25ebaca30660ec51ec1112ba4a47fd31
|
||||
EXApplication: 4797b8b37f0b0470f587fdccf6407f44b50d18b5
|
||||
EXBlur: 50d490040f3b14898ed8198d5125dc699189f4d9
|
||||
EXConstants: 7c75e5019483e84cc658c133f48607c951652465
|
||||
EXConstants: c4dd28acc12039c999612507a5f935556f2c86ce
|
||||
EXErrorRecovery: 720641265b8cf95e6cdeb1884ac38e794a352488
|
||||
EXFileSystem: 56e15a0484271771f92ccb8d75a0d77a8982fbc2
|
||||
EXFileSystem: dcf2273f49431e5037347c733a2dc5d08e0d0a9e
|
||||
EXFont: d6fb79f9863120f0d0b26b0c2d1453bc9511e9df
|
||||
EXImageLoader: da941c9399e01ec28f2d5b270bdd21f2c8ca596c
|
||||
EXKeepAwake: a4938450365c1df5a0dcc4f0be77798ca4fafc3c
|
||||
EXKeepAwake: d4e4a3ed8c1c4fd940dd62fc5a8be2a190371fd4
|
||||
EXPermissions: 67ff17d3c12ea06066492dde4242f8047658fd62
|
||||
EXSplashScreen: 9d79ea338b7bb2ee94df51723870bac70b408d44
|
||||
EXStructuredHeaders: be834496a4d9fd0069cd12ec1cc57b31c6d3b256
|
||||
EXUpdates: 79426caf9b4b781f1c2cd53d5b1bcfa3c0292e80
|
||||
EXUpdates: e191b83e00d3e7ebfd7db3986806ceca09b7b322
|
||||
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
||||
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
||||
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
||||
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
|
||||
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
||||
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
|
||||
Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c
|
||||
Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
|
||||
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
|
||||
Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7
|
||||
FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
|
||||
Flipper-RSocket: 127954abe8b162fcaf68d2134d34dc2bd7076154
|
||||
FlipperKit: 8a20b5c5fcf9436cac58551dc049867247f64b00
|
||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
||||
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
|
||||
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
||||
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
|
||||
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
|
||||
@@ -660,6 +663,7 @@ SPEC CHECKSUMS:
|
||||
React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
|
||||
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
|
||||
react-native-appearance: 0f0e5fc2fcef70e03d48c8fe6b00b9158c2ba8aa
|
||||
react-native-flipper: 5a9d5959364fca6a8a9658d941343774cb197857
|
||||
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
|
||||
react-native-viewpager: 98a850d1c7ac6263122d82618a77062a5f427073
|
||||
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
|
||||
@@ -673,7 +677,7 @@ SPEC CHECKSUMS:
|
||||
React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
|
||||
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
|
||||
RNCAsyncStorage: 08719e311ab90492c2dafd6d6fb7ffb396493638
|
||||
RNCMaskedView: 3beac403b5178d5df732dc211899ac88593d42ef
|
||||
RNCMaskedView: fc29d354a40316a990e8fb46391f08aea829c3aa
|
||||
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
|
||||
RNReanimated: 70f662b5232dd5d19ccff581e919a54ea73df51c
|
||||
RNScreens: e8e8dd0588b5da0ab57dcca76ab9b2d8987757e0
|
||||
@@ -688,12 +692,12 @@ SPEC CHECKSUMS:
|
||||
UMFontInterface: 5843cff7db85a42ba629aaac53d33091c35524d3
|
||||
UMImageLoaderInterface: 9ddffeb644b3f45d4eb0c2f51a2fd95fd5c8d1a4
|
||||
UMPermissionsInterface: 40b72935a7d12a3f60dc6b7bb99ce47908380cb1
|
||||
UMReactNativeAdapter: bcb723a9fa9e934edd0be337788cad54b4771b0f
|
||||
UMReactNativeAdapter: 65ada852a648fcb6674acfbfe72ccb095f2f5b75
|
||||
UMSensorsInterface: a5e9db661e5d9ae214762033d725989880ae6993
|
||||
UMTaskManagerInterface: 203c11259d2699b5b3a4eda4adbc466f5cb5c561
|
||||
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: b81676504862e17e403cd20d13384c8578f775b2
|
||||
PODFILE CHECKSUM: 559ae797e06704acfdd4e8aabc341b8c11a0bd5e
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
|
||||
65ECC95A68A375172205A7FF /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -227,6 +228,24 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
65ECC95A68A375172205A7FF /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ReactNavigation/Pods-ReactNavigation-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNavigation/Pods-ReactNavigation-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "ReactNavigation.app"
|
||||
BuildableName = "example.app"
|
||||
BlueprintName = "ReactNavigation"
|
||||
ReferencedContainer = "container:ReactNavigation.xcodeproj">
|
||||
</BuildableReference>
|
||||
@@ -55,7 +55,7 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "ReactNavigation.app"
|
||||
BuildableName = "example.app"
|
||||
BlueprintName = "ReactNavigation"
|
||||
ReferencedContainer = "container:ReactNavigation.xcodeproj">
|
||||
</BuildableReference>
|
||||
@@ -72,7 +72,7 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "ReactNavigation.app"
|
||||
BuildableName = "example.app"
|
||||
BlueprintName = "ReactNavigation"
|
||||
ReferencedContainer = "container:ReactNavigation.xcodeproj">
|
||||
</BuildableReference>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -67,6 +67,7 @@
|
||||
"nodemon": "^2.0.6",
|
||||
"playwright": "^1.11.0",
|
||||
"pod-install": "^0.1.19",
|
||||
"react-native-flipper": "~0.80.0",
|
||||
"react-test-renderer": "~16.13.1",
|
||||
"serve": "^11.3.0",
|
||||
"typescript": "~4.2.3"
|
||||
|
||||
@@ -37,7 +37,10 @@ import {
|
||||
HeaderStyleInterpolators,
|
||||
StackNavigationProp,
|
||||
} from '@react-navigation/stack';
|
||||
import { useReduxDevToolsExtension } from '@react-navigation/devtools';
|
||||
import {
|
||||
useReduxDevToolsExtension,
|
||||
useFlipper,
|
||||
} from '@react-navigation/devtools';
|
||||
|
||||
import { restartApp } from './Restart';
|
||||
import SettingsItem from './Shared/SettingsItem';
|
||||
@@ -209,6 +212,7 @@ export default function App() {
|
||||
const navigationRef = useNavigationContainerRef();
|
||||
|
||||
useReduxDevToolsExtension(navigationRef);
|
||||
useFlipper(navigationRef);
|
||||
|
||||
if (!isReady) {
|
||||
return null;
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
"packages": [
|
||||
"packages/*",
|
||||
"example"
|
||||
],
|
||||
"nohoist": [
|
||||
"flipper-plugin-react-navigation/flipper",
|
||||
"flipper-plugin-react-navigation/flipper-pkg",
|
||||
"flipper-plugin-react-navigation/flipper-pkg/**"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@@ -36,20 +36,23 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^6.0.0-next.8",
|
||||
"deep-equal": "^2.0.5"
|
||||
"deep-equal": "^2.0.5",
|
||||
"nanoid": "^3.1.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-navigation/core": "^6.0.0-next.8",
|
||||
"@testing-library/react-native": "^7.2.0",
|
||||
"@types/deep-equal": "^1.0.1",
|
||||
"@types/react": "^16.9.53",
|
||||
"del-cli": "^3.0.1",
|
||||
"react": "~16.13.1",
|
||||
"react-native-builder-bob": "^0.18.1",
|
||||
"react-native-flipper": "^0.80.0",
|
||||
"typescript": "^4.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-native-flipper": "*"
|
||||
},
|
||||
"react-native-builder-bob": {
|
||||
"source": "src",
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
const noop: any = () => {};
|
||||
|
||||
export let useReduxDevToolsExtension: typeof import('./useReduxDevToolsExtension').default;
|
||||
export let useFlipper: typeof import('./useFlipper').default;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
useReduxDevToolsExtension = require('./useReduxDevToolsExtension').default;
|
||||
useFlipper = require('./useFlipper').default;
|
||||
} else {
|
||||
useReduxDevToolsExtension = noop;
|
||||
useFlipper = noop;
|
||||
}
|
||||
|
||||
111
packages/devtools/src/useDevToolsBase.tsx
Normal file
111
packages/devtools/src/useDevToolsBase.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import * as React from 'react';
|
||||
import type {
|
||||
NavigationContainerRef,
|
||||
NavigationState,
|
||||
NavigationAction,
|
||||
} from '@react-navigation/core';
|
||||
import deepEqual from 'deep-equal';
|
||||
|
||||
export default function useDevToolsBase(
|
||||
ref: React.RefObject<NavigationContainerRef<any>>,
|
||||
callback: (
|
||||
...args:
|
||||
| [type: 'init', state: NavigationState | undefined]
|
||||
| [
|
||||
type: 'action',
|
||||
action: NavigationAction,
|
||||
state: NavigationState | undefined
|
||||
]
|
||||
) => void
|
||||
) {
|
||||
const lastStateRef = React.useRef<NavigationState | undefined>();
|
||||
const lastActionRef = React.useRef<NavigationAction | undefined>();
|
||||
const callbackRef = React.useRef(callback);
|
||||
const lastResetRef = React.useRef<NavigationState | undefined>(undefined);
|
||||
|
||||
React.useEffect(() => {
|
||||
callbackRef.current = callback;
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
let timer: number;
|
||||
let unsubscribeAction: (() => void) | undefined;
|
||||
let unsubscribeState: (() => void) | undefined;
|
||||
|
||||
const initialize = async () => {
|
||||
if (!ref.current) {
|
||||
// If the navigation object isn't ready yet, wait for it
|
||||
await new Promise<void>((resolve) => {
|
||||
timer = setInterval(() => {
|
||||
if (ref.current) {
|
||||
resolve();
|
||||
clearTimeout(timer);
|
||||
const state = ref.current.getRootState();
|
||||
|
||||
lastStateRef.current = state;
|
||||
callbackRef.current('init', state);
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
const navigation = ref.current!;
|
||||
|
||||
unsubscribeAction = navigation.addListener('__unsafe_action__', (e) => {
|
||||
const action = e.data.action;
|
||||
|
||||
if (e.data.noop) {
|
||||
// Even if the state didn't change, it's useful to show the action
|
||||
callbackRef.current('action', action, lastStateRef.current);
|
||||
} else {
|
||||
lastActionRef.current = action;
|
||||
}
|
||||
});
|
||||
|
||||
unsubscribeState = navigation.addListener('state', (e) => {
|
||||
// Don't show the action in dev tools if the state is what we sent to reset earlier
|
||||
if (
|
||||
lastResetRef.current &&
|
||||
deepEqual(lastResetRef.current, e.data.state)
|
||||
) {
|
||||
lastStateRef.current = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const state = navigation.getRootState();
|
||||
const lastState = lastStateRef.current;
|
||||
const action = lastActionRef.current;
|
||||
|
||||
lastActionRef.current = undefined;
|
||||
lastStateRef.current = state;
|
||||
|
||||
// If we don't have an action and the state didn't change, then it's probably extraneous
|
||||
if (action === undefined && deepEqual(state, lastState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
callbackRef.current('action', action ?? { type: '@@UNKNOWN' }, state);
|
||||
});
|
||||
};
|
||||
|
||||
initialize();
|
||||
|
||||
return () => {
|
||||
unsubscribeAction?.();
|
||||
unsubscribeState?.();
|
||||
clearTimeout(timer);
|
||||
};
|
||||
}, [ref]);
|
||||
|
||||
const resetRoot = React.useCallback(
|
||||
(state: NavigationState) => {
|
||||
if (ref.current) {
|
||||
lastResetRef.current = state;
|
||||
ref.current.resetRoot(state);
|
||||
}
|
||||
},
|
||||
[ref]
|
||||
);
|
||||
|
||||
return { resetRoot };
|
||||
}
|
||||
95
packages/devtools/src/useFlipper.tsx
Normal file
95
packages/devtools/src/useFlipper.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import * as React from 'react';
|
||||
import { addPlugin, Flipper } from 'react-native-flipper';
|
||||
import type { NavigationContainerRef } from '@react-navigation/core';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import useDevToolsBase from './useDevToolsBase';
|
||||
|
||||
export default function useFlipper(
|
||||
ref: React.RefObject<NavigationContainerRef<any>>
|
||||
) {
|
||||
const connectionRef = React.useRef<Flipper.FlipperConnection>();
|
||||
|
||||
const { resetRoot } = useDevToolsBase(ref, (...args) => {
|
||||
const connection = connectionRef.current;
|
||||
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0]) {
|
||||
case 'init':
|
||||
connection.send('init', {
|
||||
id: nanoid(),
|
||||
state: args[1],
|
||||
});
|
||||
break;
|
||||
case 'action':
|
||||
connection.send('action', {
|
||||
id: nanoid(),
|
||||
action: args[1],
|
||||
state: args[2],
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
addPlugin({
|
||||
getId() {
|
||||
return 'react-navigation';
|
||||
},
|
||||
async onConnect(connection) {
|
||||
connectionRef.current = connection;
|
||||
|
||||
const on = (event: string, listener: (params: any) => Promise<any>) => {
|
||||
connection.receive(event, (params, responder) => {
|
||||
try {
|
||||
const result = listener(params);
|
||||
|
||||
// Return null instead of undefined, otherwise flipper doesn't respond
|
||||
responder.success(result ?? null);
|
||||
} catch (e) {
|
||||
responder.error(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
on('navigation.invoke', ({ method, args = [] }) => {
|
||||
switch (method) {
|
||||
case 'resetRoot':
|
||||
return resetRoot(args[0]);
|
||||
default:
|
||||
// @ts-expect-error: we want to call arbitrary methods here
|
||||
return ref.current?.[method](...args);
|
||||
}
|
||||
});
|
||||
|
||||
on('linking.invoke', ({ method, args = [] }) => {
|
||||
// @ts-expect-error: __linking isn't publicly exposed
|
||||
const linking = ref.current?.__linking;
|
||||
|
||||
switch (method) {
|
||||
case 'getStateFromPath':
|
||||
case 'getPathFromState':
|
||||
case 'getActionFromState':
|
||||
return linking?.[method](
|
||||
args[0],
|
||||
args[1]?.trim()
|
||||
? // eslint-disable-next-line no-eval
|
||||
eval(`(function() { return ${args[1]}; }())`)
|
||||
: linking.config
|
||||
);
|
||||
default:
|
||||
return linking?.[method](...args);
|
||||
}
|
||||
});
|
||||
},
|
||||
onDisconnect() {
|
||||
connectionRef.current = undefined;
|
||||
},
|
||||
runInBackground() {
|
||||
return false;
|
||||
},
|
||||
});
|
||||
}, [ref, resetRoot]);
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import type {
|
||||
NavigationContainerRef,
|
||||
NavigationState,
|
||||
NavigationAction,
|
||||
} from '@react-navigation/core';
|
||||
import deepEqual from 'deep-equal';
|
||||
import type { NavigationContainerRef } from '@react-navigation/core';
|
||||
import useDevToolsBase from './useDevToolsBase';
|
||||
|
||||
type DevToolsConnection = {
|
||||
init(value: any): void;
|
||||
@@ -35,8 +31,22 @@ export default function useReduxDevToolsExtension(
|
||||
});
|
||||
}
|
||||
|
||||
const lastStateRef = React.useRef<NavigationState | undefined>();
|
||||
const lastActionRef = React.useRef<NavigationAction | undefined>();
|
||||
const { resetRoot } = useDevToolsBase(ref, (...args) => {
|
||||
const devTools = devToolsRef.current;
|
||||
|
||||
if (!devTools) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0]) {
|
||||
case 'init':
|
||||
devTools.init(args[1]);
|
||||
break;
|
||||
case 'action':
|
||||
devTools.send(args[1], args[2]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
React.useEffect(
|
||||
() =>
|
||||
@@ -44,66 +54,9 @@ export default function useReduxDevToolsExtension(
|
||||
if (message.type === 'DISPATCH' && message.state) {
|
||||
const state = JSON.parse(message.state);
|
||||
|
||||
lastStateRef.current = state;
|
||||
ref.current?.resetRoot(state);
|
||||
resetRoot(state);
|
||||
}
|
||||
}),
|
||||
[ref]
|
||||
[resetRoot]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
const devTools = devToolsRef.current;
|
||||
const navigation = ref.current;
|
||||
|
||||
if (!navigation || !devTools) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastStateRef.current === undefined) {
|
||||
const state = navigation.getRootState();
|
||||
|
||||
devTools.init(state);
|
||||
lastStateRef.current = state;
|
||||
}
|
||||
|
||||
const unsubscribeAction = navigation.addListener(
|
||||
'__unsafe_action__',
|
||||
(e) => {
|
||||
const action = e.data.action;
|
||||
|
||||
if (e.data.noop) {
|
||||
// Even if the state didn't change, it's useful to show the action
|
||||
devTools.send(action, lastStateRef.current);
|
||||
} else {
|
||||
lastActionRef.current = action;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const unsubscribeState = navigation.addListener('state', (e) => {
|
||||
// Don't show the action in dev tools if the state is what we sent to reset earlier
|
||||
if (lastStateRef.current === e.data.state) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastState = lastStateRef.current;
|
||||
const state = navigation.getRootState();
|
||||
const action = lastActionRef.current;
|
||||
|
||||
lastActionRef.current = undefined;
|
||||
lastStateRef.current = state;
|
||||
|
||||
// If we don't have an action and the state didn't change, then it's probably extraneous
|
||||
if (action === undefined && deepEqual(state, lastState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
devTools.send(action ?? '@@UNKNOWN', state);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribeAction();
|
||||
unsubscribeState();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
7
packages/flipper-plugin-react-navigation/babel.config.js
Normal file
7
packages/flipper-plugin-react-navigation/babel.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@babel/preset-typescript',
|
||||
'@babel/preset-react',
|
||||
['@babel/preset-env', { targets: { node: '14' } }],
|
||||
],
|
||||
};
|
||||
44
packages/flipper-plugin-react-navigation/package.json
Normal file
44
packages/flipper-plugin-react-navigation/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"$schema": "https://fbflipper.com/schemas/plugin-package/v2.json",
|
||||
"name": "flipper-plugin-react-navigation",
|
||||
"id": "react-navigation",
|
||||
"version": "1.0.0",
|
||||
"pluginType": "client",
|
||||
"main": "dist/bundle.js",
|
||||
"flipperBundlerEntry": "src/index.tsx",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"flipper-plugin"
|
||||
],
|
||||
"icon": "directions",
|
||||
"title": "React Navigation",
|
||||
"scripts": {
|
||||
"lint": "flipper-pkg lint",
|
||||
"prepack": "flipper-pkg lint && flipper-pkg bundle",
|
||||
"build": "flipper-pkg bundle",
|
||||
"watch": "flipper-pkg bundle --watch",
|
||||
"test": "jest --no-watchman"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"antd": "*",
|
||||
"flipper": "*",
|
||||
"flipper-plugin": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/icons": "^4.6.2",
|
||||
"@babel/preset-react": "^7.12.13",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@react-navigation/core": "^6.0.0-next.8",
|
||||
"@types/react": "^17.0.3",
|
||||
"@types/react-dom": "^17.0.2",
|
||||
"antd": "^4.14.0",
|
||||
"flipper": "^0.90.2",
|
||||
"flipper-pkg": "^0.90.2",
|
||||
"flipper-plugin": "^0.90.2",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"shortid": "^2.2.16"
|
||||
}
|
||||
}
|
||||
129
packages/flipper-plugin-react-navigation/src/LinkingTester.tsx
Normal file
129
packages/flipper-plugin-react-navigation/src/LinkingTester.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import * as React from 'react';
|
||||
import { DetailSidebar, styled } from 'flipper';
|
||||
import { theme } from 'flipper-plugin';
|
||||
import { Input } from 'antd';
|
||||
import type {
|
||||
getStateFromPath,
|
||||
getActionFromState,
|
||||
} from '@react-navigation/core';
|
||||
import { RouteMap } from './RouteMap';
|
||||
import { Sidebar } from './Sidebar';
|
||||
import type { StoreType } from './types';
|
||||
|
||||
type Props = StoreType & {
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
export function LinkingTester({ linking, active }: Props) {
|
||||
const [rawConfig, setRawConfig] = React.useState('');
|
||||
const [path, setPath] = React.useState('');
|
||||
|
||||
const [state, setState] = React.useState<
|
||||
ReturnType<typeof getStateFromPath> | undefined
|
||||
>();
|
||||
|
||||
const [action, setAction] = React.useState<
|
||||
ReturnType<typeof getActionFromState> | undefined
|
||||
>();
|
||||
|
||||
const [error, setError] = React.useState<string | undefined>();
|
||||
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const state = await linking(
|
||||
'getStateFromPath',
|
||||
path.replace(/(^\w+:|^)\/\//, ''),
|
||||
rawConfig
|
||||
);
|
||||
|
||||
const action = state
|
||||
? await linking('getActionFromState', state, rawConfig)
|
||||
: undefined;
|
||||
|
||||
setState(state);
|
||||
setAction(action);
|
||||
setError(undefined);
|
||||
} catch (e) {
|
||||
setState(undefined);
|
||||
setAction(undefined);
|
||||
setError(
|
||||
e?.message ||
|
||||
'Failed to parse the path. Make sure that the path matches the patterns specified in the config.'
|
||||
);
|
||||
}
|
||||
})();
|
||||
}, [linking, path, rawConfig]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<CodeInput
|
||||
type="text"
|
||||
value={path}
|
||||
placeholder="Type a path to display parsed screens, e.g. /users/@vergil"
|
||||
onChange={(e) => setPath(e.target.value)}
|
||||
/>
|
||||
<Details>
|
||||
<Summary>Custom configuration (Advanced)</Summary>
|
||||
<CodeEditor
|
||||
rows={5}
|
||||
value={rawConfig}
|
||||
placeholder="Type a custom linking config (leave empty to use the config defined in the app)"
|
||||
onChange={(e) => setRawConfig(e.target.value)}
|
||||
/>
|
||||
</Details>
|
||||
<Section>
|
||||
{state ? (
|
||||
<RouteMap routes={state.routes} />
|
||||
) : error ? (
|
||||
<ErrorDescription>Error: {error}</ErrorDescription>
|
||||
) : null}
|
||||
{active ? (
|
||||
<DetailSidebar>
|
||||
{action && <Sidebar action={action} state={state} />}
|
||||
</DetailSidebar>
|
||||
) : null}
|
||||
</Section>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const Container = styled.div({
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
});
|
||||
|
||||
const Summary = styled.summary({
|
||||
margin: `0 ${theme.space.large}px`,
|
||||
});
|
||||
|
||||
const Section = styled.div({
|
||||
margin: `${theme.space.large}px 0`,
|
||||
});
|
||||
|
||||
const Details = styled.details({
|
||||
margin: `${theme.space.large}px 0`,
|
||||
});
|
||||
|
||||
const CodeInput = styled(Input)({
|
||||
display: 'block',
|
||||
fontFamily: theme.monospace.fontFamily,
|
||||
fontSize: theme.monospace.fontSize,
|
||||
padding: theme.space.medium,
|
||||
margin: theme.space.large,
|
||||
width: `calc(100% - ${theme.space.large * 2}px)`,
|
||||
});
|
||||
|
||||
const CodeEditor = styled(Input.TextArea)({
|
||||
display: 'block',
|
||||
fontFamily: theme.monospace.fontFamily,
|
||||
fontSize: theme.monospace.fontSize,
|
||||
padding: theme.space.medium,
|
||||
margin: theme.space.large,
|
||||
width: `calc(100% - ${theme.space.large * 2}px)`,
|
||||
});
|
||||
|
||||
const ErrorDescription = styled.p({
|
||||
margin: theme.space.huge,
|
||||
color: theme.errorColor,
|
||||
});
|
||||
128
packages/flipper-plugin-react-navigation/src/Logs.tsx
Normal file
128
packages/flipper-plugin-react-navigation/src/Logs.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import * as React from 'react';
|
||||
import { CompassOutlined } from '@ant-design/icons';
|
||||
import { DetailSidebar, VirtualList, styled } from 'flipper';
|
||||
import { theme } from 'flipper-plugin';
|
||||
import { Sidebar } from './Sidebar';
|
||||
import type { StoreType } from './types';
|
||||
|
||||
type Props = StoreType & {
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
export function Logs({ active, logs, index, resetTo }: Props) {
|
||||
const [selectedID, setSelectedID] = React.useState<string | null>(null);
|
||||
|
||||
const selectedItem = selectedID
|
||||
? logs.find((log) => log.id === selectedID)
|
||||
: logs[logs.length - 1];
|
||||
|
||||
return logs.length ? (
|
||||
<>
|
||||
<VirtualList
|
||||
data={logs}
|
||||
rowHeight={51}
|
||||
renderRow={({ id, action }, i) => (
|
||||
<Row
|
||||
key={id}
|
||||
selected={selectedItem?.id === id}
|
||||
faded={index != null ? index > -1 && i > index : false}
|
||||
onClick={() => {
|
||||
if (id === logs[logs.length - 1].id) {
|
||||
setSelectedID(null);
|
||||
} else {
|
||||
setSelectedID(id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{action.type}
|
||||
<JumpButton type="button" onClick={() => resetTo(id)}>
|
||||
Reset to this
|
||||
</JumpButton>
|
||||
</Row>
|
||||
)}
|
||||
/>
|
||||
{active ? (
|
||||
<DetailSidebar>
|
||||
{selectedItem && (
|
||||
<Sidebar action={selectedItem.action} state={selectedItem.state} />
|
||||
)}
|
||||
</DetailSidebar>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<Center>
|
||||
<Faded>
|
||||
<EmptyIcon />
|
||||
<BlankslateText>Navigate in the app to see actions</BlankslateText>
|
||||
</Faded>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
const Row = styled.button<{ selected: boolean; faded: boolean }>((props) => ({
|
||||
'appearance': 'none',
|
||||
'display': 'flex',
|
||||
'alignItems': 'center',
|
||||
'justifyContent': 'space-between',
|
||||
'fontFamily': theme.monospace.fontFamily,
|
||||
'fontSize': theme.monospace.fontSize,
|
||||
'textAlign': 'left',
|
||||
'padding': `${theme.space.medium}px ${theme.space.large}px`,
|
||||
'color': props.selected ? '#fff' : '#000',
|
||||
'backgroundColor': props.selected ? theme.primaryColor : 'transparent',
|
||||
'opacity': props.faded ? 0.5 : 1,
|
||||
'border': 0,
|
||||
'boxShadow': `inset 0 -1px 0 0 ${theme.dividerColor}`,
|
||||
'width': '100%',
|
||||
'cursor': 'pointer',
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: props.selected
|
||||
? theme.primaryColor
|
||||
: 'rgba(0, 0, 0, 0.05)',
|
||||
},
|
||||
}));
|
||||
|
||||
const JumpButton = styled.button({
|
||||
'appearance': 'none',
|
||||
'backgroundColor': 'rgba(0, 0, 0, 0.1)',
|
||||
'border': 0,
|
||||
'margin': 0,
|
||||
'padding': `${theme.space.tiny}px ${theme.space.medium}px`,
|
||||
'color': 'inherit',
|
||||
'cursor': 'pointer',
|
||||
'fontSize': theme.fontSize.small,
|
||||
'borderRadius': theme.borderRadius,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
});
|
||||
|
||||
const Center = styled.div({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
});
|
||||
|
||||
const Faded = styled.div({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
opacity: 0.3,
|
||||
});
|
||||
|
||||
const EmptyIcon = styled(CompassOutlined)({
|
||||
display: 'block',
|
||||
fontSize: 48,
|
||||
margin: theme.space.large,
|
||||
opacity: 0.8,
|
||||
});
|
||||
|
||||
const BlankslateText = styled.h5({
|
||||
color: 'rgba(0, 0, 0, 0.85)',
|
||||
fontWeight: 600,
|
||||
fontSize: 16,
|
||||
lineHeight: 1.5,
|
||||
});
|
||||
146
packages/flipper-plugin-react-navigation/src/RouteMap.tsx
Normal file
146
packages/flipper-plugin-react-navigation/src/RouteMap.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import * as React from 'react';
|
||||
import { styled } from 'flipper';
|
||||
import { theme } from 'flipper-plugin';
|
||||
import type { PartialRoute } from './types';
|
||||
|
||||
type Props = {
|
||||
routes: PartialRoute[];
|
||||
root?: boolean;
|
||||
};
|
||||
|
||||
export function RouteMap({ routes, root = true }: Props) {
|
||||
return (
|
||||
<Container
|
||||
style={{
|
||||
...(root
|
||||
? { overflowX: 'auto', padding: `0 ${theme.space.small}px` }
|
||||
: null),
|
||||
}}
|
||||
>
|
||||
{routes.map((route, i) => (
|
||||
<Item key={route.name}>
|
||||
<div>
|
||||
<Name>
|
||||
{route.name}
|
||||
{root ? null : i === 0 ? <ConnectLeft /> : <ConnectUpLeft />}
|
||||
</Name>
|
||||
{route.params ? (
|
||||
<ParamsContainer>
|
||||
<Params>
|
||||
<tbody>
|
||||
{Object.entries(route.params).map(([key, value]) => (
|
||||
<Row key={key}>
|
||||
<Key>{key}</Key>
|
||||
<Separator>:</Separator>
|
||||
<Value>{JSON.stringify(value)}</Value>
|
||||
</Row>
|
||||
))}
|
||||
</tbody>
|
||||
</Params>
|
||||
<ConnectUp />
|
||||
</ParamsContainer>
|
||||
) : null}
|
||||
</div>
|
||||
{route.state ? (
|
||||
<RouteMap routes={route.state.routes} root={false} />
|
||||
) : null}
|
||||
</Item>
|
||||
))}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const Container = styled.div({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
const Item = styled.div({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
});
|
||||
|
||||
const Name = styled.div({
|
||||
minWidth: 120,
|
||||
backgroundColor: theme.primaryColor,
|
||||
color: 'white',
|
||||
fontSize: theme.fontSize.default,
|
||||
margin: theme.space.small,
|
||||
padding: `${theme.space.small}px ${theme.space.large}px`,
|
||||
borderRadius: theme.borderRadius,
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
});
|
||||
|
||||
const ParamsContainer = styled.div({
|
||||
position: 'relative',
|
||||
});
|
||||
|
||||
const Params = styled.table({
|
||||
minWidth: 120,
|
||||
borderCollapse: 'separate',
|
||||
border: `1px solid ${theme.primaryColor}`,
|
||||
fontFamily: theme.monospace.fontFamily,
|
||||
fontSize: theme.monospace.fontSize,
|
||||
margin: `${theme.space.large}px ${theme.space.small}px`,
|
||||
padding: theme.space.small,
|
||||
borderRadius: theme.borderRadius,
|
||||
width: 'auto',
|
||||
overflow: 'visible',
|
||||
});
|
||||
|
||||
const Row = styled.tr({
|
||||
border: 0,
|
||||
background: 'none',
|
||||
});
|
||||
|
||||
const Key = styled.td({
|
||||
color: theme.textColorSecondary,
|
||||
border: 0,
|
||||
padding: '0 4px',
|
||||
textAlign: 'right',
|
||||
});
|
||||
|
||||
const Value = styled.td({
|
||||
color: theme.primaryColor,
|
||||
padding: `0 ${theme.space.tiny}px`,
|
||||
border: 0,
|
||||
});
|
||||
|
||||
const Separator = styled.td({
|
||||
color: 'inherit',
|
||||
opacity: 0.3,
|
||||
border: 0,
|
||||
padding: 0,
|
||||
});
|
||||
|
||||
const ConnectLeft = styled.div({
|
||||
position: 'absolute',
|
||||
width: 16,
|
||||
height: 1,
|
||||
backgroundColor: theme.primaryColor,
|
||||
right: '100%',
|
||||
top: '50%',
|
||||
});
|
||||
|
||||
const ConnectUpLeft = styled.div({
|
||||
position: 'absolute',
|
||||
width: 9,
|
||||
height: 53,
|
||||
border: `1px solid ${theme.primaryColor}`,
|
||||
borderRadius: `0 0 0 ${theme.borderRadius}`,
|
||||
borderRight: 0,
|
||||
borderTop: 0,
|
||||
right: '100%',
|
||||
bottom: '50%',
|
||||
});
|
||||
|
||||
const ConnectUp = styled.div({
|
||||
position: 'absolute',
|
||||
width: 1,
|
||||
height: 16,
|
||||
backgroundColor: theme.primaryColor,
|
||||
right: '50%',
|
||||
bottom: '100%',
|
||||
});
|
||||
20
packages/flipper-plugin-react-navigation/src/Sidebar.tsx
Normal file
20
packages/flipper-plugin-react-navigation/src/Sidebar.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as React from 'react';
|
||||
import { Layout, ManagedDataInspector } from 'flipper';
|
||||
import { Title4 } from './Typography';
|
||||
|
||||
export function Sidebar({
|
||||
action,
|
||||
state,
|
||||
}: {
|
||||
action: object;
|
||||
state: object | undefined;
|
||||
}) {
|
||||
return (
|
||||
<Layout.Container gap pad>
|
||||
<Title4>Action</Title4>
|
||||
<ManagedDataInspector data={action} expandRoot={false} />
|
||||
<Title4>State</Title4>
|
||||
<ManagedDataInspector data={state} expandRoot={false} />
|
||||
</Layout.Container>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { styled } from 'flipper';
|
||||
|
||||
export const Title4 = styled.h4({
|
||||
fontWeight: 600,
|
||||
fontSize: 14,
|
||||
lineHeight: 1.4,
|
||||
letterSpacing: -0.24,
|
||||
marginBottom: 0,
|
||||
});
|
||||
40
packages/flipper-plugin-react-navigation/src/index.tsx
Normal file
40
packages/flipper-plugin-react-navigation/src/index.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import * as React from 'react';
|
||||
import { styled } from 'flipper';
|
||||
import { theme } from 'flipper-plugin';
|
||||
import { Tabs } from 'antd';
|
||||
import { useStore } from './useStore';
|
||||
import { Logs } from './Logs';
|
||||
import { LinkingTester } from './LinkingTester';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
export function Component() {
|
||||
const store = useStore();
|
||||
|
||||
const [activeKey, setActiveKey] = React.useState('logs');
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
activeKey={activeKey}
|
||||
onChange={setActiveKey}
|
||||
tabBarStyle={{ marginBottom: 0 }}
|
||||
>
|
||||
<TabsContent tab={<TabLabel>Logs</TabLabel>} key="logs">
|
||||
<Logs active={activeKey === 'logs'} {...store} />
|
||||
</TabsContent>
|
||||
<TabsContent tab={<TabLabel>Linking</TabLabel>} key="linking">
|
||||
<LinkingTester active={activeKey === 'linking'} {...store} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
const TabLabel = styled.span({
|
||||
padding: `0 ${theme.space.large}px`,
|
||||
});
|
||||
|
||||
const TabsContent = styled(TabPane)({
|
||||
height: 'calc(100vh - 80px)',
|
||||
});
|
||||
|
||||
export * from './plugin';
|
||||
63
packages/flipper-plugin-react-navigation/src/plugin.tsx
Normal file
63
packages/flipper-plugin-react-navigation/src/plugin.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { PluginClient, createState } from 'flipper-plugin';
|
||||
import type { Log, NavigationState } from './types';
|
||||
|
||||
type Events = {
|
||||
action: Log;
|
||||
init: { id: string; state: NavigationState | undefined };
|
||||
};
|
||||
|
||||
type Methods = {
|
||||
'navigation.invoke': (params: {
|
||||
method: string;
|
||||
args: any[];
|
||||
}) => Promise<any>;
|
||||
'linking.invoke': (params: { method: string; args: any[] }) => Promise<any>;
|
||||
};
|
||||
|
||||
export function plugin(client: PluginClient<Events, Methods>) {
|
||||
const logs = createState<Log[]>([], { persist: 'logs' });
|
||||
const index = createState<number | null>(null, { persist: 'index' });
|
||||
|
||||
client.onMessage('init', () => {
|
||||
logs.set([]);
|
||||
index.set(null);
|
||||
});
|
||||
|
||||
client.onMessage('action', (action) => {
|
||||
const indexValue = index.get();
|
||||
index.set(null);
|
||||
logs.update((draft) => {
|
||||
if (indexValue != null) {
|
||||
draft.splice(indexValue + 1);
|
||||
}
|
||||
draft.push(action);
|
||||
});
|
||||
});
|
||||
|
||||
function navigation(method: string, ...args: any[]) {
|
||||
return client.send('navigation.invoke', { method, args });
|
||||
}
|
||||
|
||||
function resetTo(id: string) {
|
||||
const logsValue = logs.get();
|
||||
const indexValue = logsValue.findIndex((update) => update.id === id)!;
|
||||
const { state } = logsValue[indexValue];
|
||||
index.set(indexValue);
|
||||
return client.send('navigation.invoke', {
|
||||
method: 'resetRoot',
|
||||
args: [state],
|
||||
});
|
||||
}
|
||||
|
||||
function linking(method: string, ...args: any[]) {
|
||||
return client.send('linking.invoke', { method, args });
|
||||
}
|
||||
|
||||
return {
|
||||
logs,
|
||||
index,
|
||||
resetTo,
|
||||
navigation,
|
||||
linking,
|
||||
};
|
||||
}
|
||||
41
packages/flipper-plugin-react-navigation/src/types.tsx
Normal file
41
packages/flipper-plugin-react-navigation/src/types.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
export type NavigationRoute = {
|
||||
key: string;
|
||||
name: string;
|
||||
params?: object;
|
||||
state?: NavigationState;
|
||||
};
|
||||
|
||||
export type NavigationState = {
|
||||
key: string;
|
||||
index: number;
|
||||
routes: NavigationRoute[];
|
||||
};
|
||||
|
||||
export type NavigationAction = {
|
||||
type: string;
|
||||
payload?: object;
|
||||
};
|
||||
|
||||
export type PartialRoute = {
|
||||
name: string;
|
||||
params?: object;
|
||||
state?: PartialState;
|
||||
};
|
||||
|
||||
export type PartialState = {
|
||||
routes: PartialRoute[];
|
||||
};
|
||||
|
||||
export type Log = {
|
||||
id: string;
|
||||
action: NavigationAction;
|
||||
state: NavigationState | undefined;
|
||||
};
|
||||
|
||||
export type StoreType = {
|
||||
logs: Log[];
|
||||
index: number;
|
||||
navigation: (method: string, ...args: any[]) => Promise<any>;
|
||||
linking: (method: string, ...args: any[]) => Promise<any>;
|
||||
resetTo: (id: string) => Promise<void>;
|
||||
};
|
||||
17
packages/flipper-plugin-react-navigation/src/useStore.tsx
Normal file
17
packages/flipper-plugin-react-navigation/src/useStore.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { usePlugin, useValue } from 'flipper-plugin';
|
||||
import type { StoreType } from './types';
|
||||
import { plugin } from './plugin';
|
||||
|
||||
export function useStore(): StoreType {
|
||||
const instance = usePlugin(plugin);
|
||||
const logs = useValue(instance.logs);
|
||||
const index = useValue(instance.index);
|
||||
|
||||
return {
|
||||
logs,
|
||||
index: index ?? logs.length - 1,
|
||||
navigation: instance.navigation,
|
||||
linking: instance.linking,
|
||||
resetTo: instance.resetTo,
|
||||
};
|
||||
}
|
||||
23
packages/flipper-plugin-react-navigation/tsconfig.json
Normal file
23
packages/flipper-plugin-react-navigation/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"esModuleInterop": true,
|
||||
"importsNotUsedAsValues": "error",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react",
|
||||
"lib": ["esnext", "dom"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitUseStrict": false,
|
||||
"noStrictGenericChecks": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "esnext"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
BaseNavigationContainer,
|
||||
getPathFromState,
|
||||
getStateFromPath,
|
||||
getActionFromState,
|
||||
NavigationContainerProps,
|
||||
NavigationContainerRef,
|
||||
ParamListBase,
|
||||
@@ -62,6 +65,27 @@ function NavigationContainerInner(
|
||||
...linking,
|
||||
});
|
||||
|
||||
// Add additional linking related info to the ref
|
||||
// This will be used by the devtools
|
||||
React.useEffect(() => {
|
||||
if (refContainer.current) {
|
||||
Object.defineProperty(refContainer.current, '__linking', {
|
||||
get() {
|
||||
return {
|
||||
...linking,
|
||||
enabled: isLinkingEnabled,
|
||||
prefixes: linking?.prefixes ?? [],
|
||||
getStateFromPath: linking?.getStateFromPath ?? getStateFromPath,
|
||||
getPathFromState: linking?.getPathFromState ?? getPathFromState,
|
||||
getActionFromState:
|
||||
linking?.getActionFromState ?? getActionFromState,
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const [isResolved, initialState] = useThenable(getInitialState);
|
||||
|
||||
React.useImperativeHandle(ref, () => refContainer.current);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type {
|
||||
getStateFromPath as getStateFromPathDefault,
|
||||
getPathFromState as getPathFromStateDefault,
|
||||
getActionFromState as getActionFromStateDefault,
|
||||
PathConfigMap,
|
||||
Route,
|
||||
} from '@react-navigation/core';
|
||||
@@ -104,6 +105,10 @@ export type LinkingOptions<ParamList extends {}> = {
|
||||
* Only applicable on Web.
|
||||
*/
|
||||
getPathFromState?: typeof getPathFromStateDefault;
|
||||
/**
|
||||
* Custom function to convert the state object to a valid action (advanced).
|
||||
*/
|
||||
getActionFromState?: typeof getActionFromStateDefault;
|
||||
};
|
||||
|
||||
export type DocumentTitleOptions = {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { Linking, Platform } from 'react-native';
|
||||
import {
|
||||
getActionFromState,
|
||||
getStateFromPath as getStateFromPathDefault,
|
||||
getActionFromState as getActionFromStateDefault,
|
||||
NavigationContainerRef,
|
||||
ParamListBase,
|
||||
} from '@react-navigation/core';
|
||||
@@ -45,6 +45,7 @@ export default function useLinking(
|
||||
};
|
||||
},
|
||||
getStateFromPath = getStateFromPathDefault,
|
||||
getActionFromState = getActionFromStateDefault,
|
||||
}: LinkingOptions<ParamListBase>
|
||||
) {
|
||||
React.useEffect(() => {
|
||||
@@ -78,6 +79,7 @@ export default function useLinking(
|
||||
const configRef = React.useRef(config);
|
||||
const getInitialURLRef = React.useRef(getInitialURL);
|
||||
const getStateFromPathRef = React.useRef(getStateFromPath);
|
||||
const getActionFromStateRef = React.useRef(getActionFromState);
|
||||
|
||||
React.useEffect(() => {
|
||||
enabledRef.current = enabled;
|
||||
@@ -85,7 +87,8 @@ export default function useLinking(
|
||||
configRef.current = config;
|
||||
getInitialURLRef.current = getInitialURL;
|
||||
getStateFromPathRef.current = getStateFromPath;
|
||||
}, [config, enabled, prefixes, getInitialURL, getStateFromPath]);
|
||||
getActionFromStateRef.current = getActionFromState;
|
||||
});
|
||||
|
||||
const getInitialState = React.useCallback(() => {
|
||||
let state: ResultState | undefined;
|
||||
@@ -150,7 +153,10 @@ export default function useLinking(
|
||||
return;
|
||||
}
|
||||
|
||||
const action = getActionFromState(state, configRef.current);
|
||||
const action = getActionFromStateRef.current(
|
||||
state,
|
||||
configRef.current
|
||||
);
|
||||
|
||||
if (action !== undefined) {
|
||||
try {
|
||||
|
||||
@@ -2,9 +2,9 @@ import * as React from 'react';
|
||||
import {
|
||||
getStateFromPath as getStateFromPathDefault,
|
||||
getPathFromState as getPathFromStateDefault,
|
||||
getActionFromState as getActionFromStateDefault,
|
||||
NavigationContainerRef,
|
||||
NavigationState,
|
||||
getActionFromState,
|
||||
findFocusedRoute,
|
||||
ParamListBase,
|
||||
} from '@react-navigation/core';
|
||||
@@ -295,6 +295,7 @@ export default function useLinking(
|
||||
config,
|
||||
getStateFromPath = getStateFromPathDefault,
|
||||
getPathFromState = getPathFromStateDefault,
|
||||
getActionFromState = getActionFromStateDefault,
|
||||
}: LinkingOptions<ParamListBase>
|
||||
) {
|
||||
React.useEffect(() => {
|
||||
@@ -326,13 +327,15 @@ export default function useLinking(
|
||||
const configRef = React.useRef(config);
|
||||
const getStateFromPathRef = React.useRef(getStateFromPath);
|
||||
const getPathFromStateRef = React.useRef(getPathFromState);
|
||||
const getActionFromStateRef = React.useRef(getActionFromState);
|
||||
|
||||
React.useEffect(() => {
|
||||
enabledRef.current = enabled;
|
||||
configRef.current = config;
|
||||
getStateFromPathRef.current = getStateFromPath;
|
||||
getPathFromStateRef.current = getPathFromState;
|
||||
}, [config, enabled, getPathFromState, getStateFromPath]);
|
||||
getActionFromStateRef.current = getActionFromState;
|
||||
});
|
||||
|
||||
const server = React.useContext(ServerContext);
|
||||
|
||||
@@ -413,7 +416,10 @@ export default function useLinking(
|
||||
}
|
||||
|
||||
if (index > previousIndex) {
|
||||
const action = getActionFromState(state, configRef.current);
|
||||
const action = getActionFromStateRef.current(
|
||||
state,
|
||||
configRef.current
|
||||
);
|
||||
|
||||
if (action !== undefined) {
|
||||
try {
|
||||
|
||||
@@ -24,5 +24,6 @@
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "esnext"
|
||||
}
|
||||
},
|
||||
"exclude": ["packages/flipper-plugin-react-navigation"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user