From 77a6617a39896ef4f6793b369d304444b8cf63bb Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Tue, 28 May 2019 10:17:26 -0700 Subject: [PATCH 001/330] Use JS ViewConfig for View Summary: Rick manually created view config in JS for View; adding some missing attributes/events and using this instead of `requireNativeComponent` Reviewed By: rickhanlonii Differential Revision: D15488008 fbshipit-source-id: 48e925ec0ca2aeba9e6cc66edef0b70ee1c94d27 --- .../View/ReactNativeViewViewConfig.js | 63 ++++++++++++++++++- .../Components/View/ViewNativeComponent.js | 6 +- .../verifyComponentAttributeEquivalence.js | 2 +- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index d723f2797e7de1..942a269790f1f5 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -10,12 +10,12 @@ 'use strict'; +const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); +const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); + const ReactNativeViewConfig = { uiViewClassName: 'RCTView', - baseModuleName: null, - Manager: 'ViewManager', Commands: {}, - Constants: {}, bubblingEventTypes: { topBlur: { phasedRegistrationNames: { @@ -53,6 +53,12 @@ const ReactNativeViewConfig = { captured: 'onPressCapture', }, }, + topSelect: { + phasedRegistrationNames: { + bubbled: 'onSelect', + captured: 'onSelectCapture', + }, + }, topSubmitEditing: { phasedRegistrationNames: { bubbled: 'onSubmitEditing', @@ -85,6 +91,9 @@ const ReactNativeViewConfig = { }, }, directEventTypes: { + performAction: { + registrationName: 'onAccessibilityAction', + }, topAccessibilityAction: { registrationName: 'onAccessibilityAction', }, @@ -94,12 +103,48 @@ const ReactNativeViewConfig = { topAccessibilityTap: { registrationName: 'onAccessibilityTap', }, + topClick: { + registrationName: 'onClick', + }, + topContentSizeChange: { + registrationName: 'onContentSizeChange', + }, topLayout: { registrationName: 'onLayout', }, + topLoadingError: { + registrationName: 'onLoadingError', + }, + topLoadingFinish: { + registrationName: 'onLoadingFinish', + }, + topLoadingStart: { + registrationName: 'onLoadingStart', + }, topMagicTap: { registrationName: 'onMagicTap', }, + topMessage: { + registrationName: 'onMessage', + }, + topMomentumScrollBegin: { + registrationName: 'onMomentumScrollBegin', + }, + topMomentumScrollEnd: { + registrationName: 'onMomentumScrollEnd', + }, + topScroll: { + registrationName: 'onScroll', + }, + topScrollBeginDrag: { + registrationName: 'onScrollBeginDrag', + }, + topScrollEndDrag: { + registrationName: 'onScrollEndDrag', + }, + topSelectionChange: { + registrationName: 'onSelectionChange', + }, }, validAttributes: { accessibilityActions: true, @@ -156,6 +201,7 @@ const ReactNativeViewConfig = { flexGrow: true, flexShrink: true, flexWrap: true, + hasTVPreferredFocus: true, height: true, hitSlop: {diff: (require('../../Utilities/differ/insetsDiffer'): any)}, importantForAccessibility: true, @@ -174,8 +220,15 @@ const ReactNativeViewConfig = { maxWidth: true, minHeight: true, minWidth: true, + nativeBackgroundAndroid: true, + nativeForegroundAndroid: true, nativeID: true, needsOffscreenAlphaCompositing: true, + nextFocusDown: true, + nextFocusForward: true, + nextFocusLeft: true, + nextFocusRight: true, + nextFocusUp: true, onAccessibilityAction: true, onAccessibilityEscape: true, onAccessibilityTap: true, @@ -326,4 +379,8 @@ const ReactNativeViewConfig = { }, }; +verifyComponentAttributeEquivalence('RCTView', ReactNativeViewConfig); + +ReactNativeViewConfigRegistry.register('RCTView', () => ReactNativeViewConfig); + module.exports = ReactNativeViewConfig; diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index 21e57c8a437ab5..aa7ea2b502141d 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -12,12 +12,10 @@ const ReactNative = require('../../Renderer/shims/ReactNative'); -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - import type {ViewProps} from './ViewPropTypes'; type ViewNativeComponentType = Class>; -const NativeViewComponent = requireNativeComponent('RCTView'); +require('ReactNativeViewViewConfig'); -module.exports = ((NativeViewComponent: any): ViewNativeComponentType); +module.exports = (('RCTView': any): ViewNativeComponentType); diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index 296b7837cbd7af..63c66445a159c3 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -14,7 +14,7 @@ const getNativeComponentAttributes = require('../ReactNative/getNativeComponentA import type {ReactNativeBaseComponentViewConfig} from '../Renderer/shims/ReactNativeTypes'; -const IGNORED_KEYS = ['transform']; +const IGNORED_KEYS = ['transform', 'hitSlop']; /** * The purpose of this function is to validate that the view config that * native exposes for a given view manager is the same as the view config From ab1a42762c1f7a8b0e99d70f2c1916d907e3868b Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Tue, 28 May 2019 12:07:34 -0700 Subject: [PATCH 002/330] Make RelayObservable Source return type disjoint Summary: In Flow v0.99 we are changing function type annotations to be strict about their static properties. This causes a small issue with the union of a Subcription and `() => mixed` function type, where the latter is now understood to possibly have an `unsubscribe` property with a mixed type. This causes the following refinement check, which appears lower in this file, to cause an error in the next version of Flow: ``` if (cleanup) { if (cleanup.unsubscribe) { cleanup.unsubscribe(); // <-- error here } // ... } ``` In Flow v0.99, because `() => mixed` statics are now checked, Flow sees that `cleanup.unsubscribe` might be `mixed`, which passes the conditional but could cause an exception when called. I also needed to change JestMockFn to have exact statics, because tests sometimes use a value with that type in place of the cleanup function. That runs into the `{} <: {+p?: void}` rule, which is an error. `{||} <: {+p?:void}` is not an error. Reviewed By: josephsavona Differential Revision: D15522655 fbshipit-source-id: 2ae3c9016e2b07abaac79827082d2f8743623eb5 --- flow/jest.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flow/jest.js b/flow/jest.js index 799978ca43bd27..252c05bea445c7 100644 --- a/flow/jest.js +++ b/flow/jest.js @@ -11,7 +11,7 @@ /* eslint-disable lint/no-unclear-flowtypes */ -type JestMockFn, TReturn> = { +type JestMockFn, TReturn> = {| (...args: TArguments): TReturn, /** * An object for introspecting mock calls @@ -105,7 +105,7 @@ type JestMockFn, TReturn> = { * Sugar for jest.fn().mockImplementationOnce(() => Promise.reject(value)) */ mockRejectedValueOnce(value: TReturn): JestMockFn>, -}; +|}; type JestAsymmetricEqualityType = { /** @@ -794,7 +794,7 @@ type JestObjectType = { * Returns a new, unused mock function. Optionally takes a mock * implementation. */ - fn, TReturn>( + fn, TReturn>( implementation?: (...args: TArguments) => TReturn, ): JestMockFn, /** From 298f59c5d38424836381faae93a2a782450e2ad4 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Tue, 28 May 2019 12:14:36 -0700 Subject: [PATCH 003/330] Use startSurface on Android Summary: We currently have two different codepaths for actually rendering a surface with Fabric on iOS and Android: on iOS we use Fabric's `UIManagerBinding.startSurface` to call `AppRegistry.runApplication`, but on Android we don't; instead we use the same codepath as paper, calling `ReactRootView.runApplication`. This diff does a few different things: 1. Unify iOS and Android by removing the `#ifndef` for Android so that we call `startSurface` for both 2. Pass through the JS module name on Android so that this actually works (it currently passes in an empty string) 3. Remove the call to `ReactRootView.runApplication` for Fabric so that we don't end up doing this twice 4. Copy over some logic that we need from `ReactRootView.runApplication` (make sure that root layout specs get updated, and that content appeared gets logged) Reviewed By: mdvacca Differential Revision: D15501666 fbshipit-source-id: 5c96c8cf036261cb99729b1dbdff0f7c09a32d76 --- .../facebook/react/ReactInstanceManager.java | 18 +++++++++---- .../com/facebook/react/ReactRootView.java | 27 ++++++++++++------- .../com/facebook/react/fabric/Binding.java | 2 +- .../react/fabric/FabricUIManager.java | 10 +++++-- .../com/facebook/react/fabric/jni/Binding.cpp | 8 ++++-- .../com/facebook/react/fabric/jni/Binding.h | 5 +++- .../facebook/react/uimanager/ReactRoot.java | 12 +++++++++ ReactCommon/fabric/uimanager/Scheduler.cpp | 4 --- 8 files changed, 62 insertions(+), 24 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 8c8bd4ceb6fa7b..e9513a059352bc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -1050,16 +1050,24 @@ public void run() { private void attachRootViewToInstance(final ReactRoot reactRoot) { Log.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()"); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance"); - UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType()); + UIManager uiManager = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType()); @Nullable Bundle initialProperties = reactRoot.getAppProperties(); - final int rootTag = uiManagerModule.addRootView( - reactRoot.getRootViewGroup(), - initialProperties == null ? + + final int rootTag = uiManager.addRootView( + reactRoot.getRootViewGroup(), + initialProperties == null ? new WritableNativeMap() : Arguments.fromBundle(initialProperties), reactRoot.getInitialUITemplate()); reactRoot.setRootViewTag(rootTag); - reactRoot.runApplication(); + if (reactRoot.getUIManagerType() == FABRIC) { + // Fabric requires to call updateRootLayoutSpecs before starting JS Application, + // this ensures the root will hace the correct pointScaleFactor. + uiManager.updateRootLayoutSpecs(rootTag, reactRoot.getWidthMeasureSpec(), reactRoot.getHeightMeasureSpec()); + reactRoot.setShouldLogContentAppeared(true); + } else { + reactRoot.runApplication(); + } Systrace.beginAsyncSection( TRACE_TAG_REACT_JAVA_BRIDGE, "pre_rootView.onAttachedToReactInstance", diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 37341ca9242422..3cf5a45d3a85fb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -405,6 +405,21 @@ public void startReactApplication( } } + @Override + public int getWidthMeasureSpec() { + return mWidthMeasureSpec; + } + + @Override + public int getHeightMeasureSpec() { + return mHeightMeasureSpec; + } + + @Override + public void setShouldLogContentAppeared(boolean shouldLogContentAppeared) { + mShouldLogContentAppeared = shouldLogContentAppeared; + } + private void updateRootLayoutSpecs(final int widthMeasureSpec, final int heightMeasureSpec) { if (mReactInstanceManager == null) { FLog.w( @@ -461,7 +476,8 @@ public void setEventListener(ReactRootViewEventListener eventListener) { mRootViewEventListener = eventListener; } - /* package */ String getJSModuleName() { + @Override + public String getJSModuleName() { return Assertions.assertNotNull(mJSModuleName); } @@ -506,11 +522,7 @@ public void runApplication() { if (mUseSurface) { // TODO call surface's runApplication } else { - - boolean isFabric = getUIManagerType() == FABRIC; - // Fabric requires to call updateRootLayoutSpecs before starting JS Application, - // this ensures the root will hace the correct pointScaleFactor. - if (mWasMeasured || isFabric) { + if (mWasMeasured) { updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); } @@ -520,9 +532,6 @@ public void runApplication() { if (appProperties != null) { appParams.putMap("initialProps", Arguments.fromBundle(appProperties)); } - if (isFabric) { - appParams.putBoolean("fabric", true); - } mShouldLogContentAppeared = true; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java index cd2557a4357af4..c41b5bcbe46a75 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java @@ -39,7 +39,7 @@ private native void installFabricUIManager( ComponentFactoryDelegate componentsRegistry, Object reactNativeConfig); - public native void startSurface(int surfaceId, NativeMap initialProps); + public native void startSurface(int surfaceId, String moduleName, NativeMap initialProps); public native void renderTemplateToSurface(int surfaceId, String uiTemplate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 880f9a827c92bd..2741bb08f92630 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -53,6 +53,7 @@ import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateStateMountItem; import com.facebook.react.modules.core.ReactChoreographer; +import com.facebook.react.uimanager.ReactRoot; import com.facebook.react.uimanager.ReactRootViewTagGenerator; import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; @@ -127,13 +128,18 @@ public FabricUIManager( @Override public int addRootView( - final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { + final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { + return addRootView(rootView, ((ReactRoot) rootView).getJSModuleName(), initialProps, initialUITemplate); + } + + public int addRootView( + final T rootView, final String moduleName, final WritableMap initialProps, final @Nullable String initialUITemplate) { final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext reactContext = new ThemedReactContext(mReactApplicationContext, rootView.getContext()); mMountingManager.addRootView(rootTag, rootView); mReactContextForRootTag.put(rootTag, reactContext); - mBinding.startSurface(rootTag, (NativeMap) initialProps); + mBinding.startSurface(rootTag, moduleName, (NativeMap) initialProps); if (initialUITemplate != null) { mBinding.renderTemplateToSurface(rootTag, initialUITemplate); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 4effb64e1a0fe0..e38edd549d76bf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -45,9 +45,13 @@ jni::local_ref Binding::initHybrid( return makeCxxInstance(); } -void Binding::startSurface(jint surfaceId, NativeMap *initialProps) { +void Binding::startSurface( + jint surfaceId, + jni::alias_ref moduleName, + NativeMap *initialProps) { if (scheduler_) { - scheduler_->startSurface(surfaceId, "", initialProps->consume()); + scheduler_->startSurface( + surfaceId, moduleName->toStdString(), initialProps->consume()); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h index 588e94740f8a91..2a880bc2d8bac4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h @@ -50,7 +50,10 @@ class Binding : public jni::HybridClass, public SchedulerDelegate { ComponentFactoryDelegate *componentsRegistry, jni::alias_ref reactNativeConfig); - void startSurface(jint surfaceId, NativeMap *initialProps); + void startSurface( + jint surfaceId, + jni::alias_ref moduleName, + NativeMap *initialProps); void renderTemplateToSurface(jint surfaceId, jstring uiTemplate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java index c56216ded0dec9..67db02992660d6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java @@ -23,6 +23,7 @@ public interface ReactRoot { */ @Nullable Bundle getAppProperties(); @Nullable String getInitialUITemplate(); + String getJSModuleName(); /** * Fabric or Default UI Manager, see {@link UIManagerType} @@ -47,4 +48,15 @@ public interface ReactRoot { * Return native view for root */ ViewGroup getRootViewGroup(); + + /** + * @return Cached values for widthMeasureSpec and heightMeasureSpec + */ + int getWidthMeasureSpec(); + int getHeightMeasureSpec(); + + /** + * Sets a flag that determines whether to log that content appeared on next view added. + */ + void setShouldLogContentAppeared(boolean shouldLogContentAppeared); } diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index c4637c1a3d5bed..aab1121d9341e8 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -96,12 +96,10 @@ void Scheduler::startSurface( shadowTreeRegistry_.add(std::move(shadowTree)); -#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->startSurface( runtime, surfaceId, moduleName, initialProps); }); -#endif } void Scheduler::renderTemplateToSurface( @@ -171,11 +169,9 @@ void Scheduler::stopSurface(SurfaceId surfaceId) const { auto shadowTree = shadowTreeRegistry_.remove(surfaceId); shadowTree->setDelegate(nullptr); -#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->stopSurface(runtime, surfaceId); }); -#endif } Size Scheduler::measureSurface( From d83ba5ad51abb110819f2a65a69ac3cd865bffdd Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Tue, 28 May 2019 16:31:56 -0700 Subject: [PATCH 004/330] Revert D15488008: Use JS ViewConfig for View Differential Revision: D15488008 Original commit changeset: 48e925ec0ca2 fbshipit-source-id: 4ffa223e636116777c178386b6e966a4f253c30a --- .../View/ReactNativeViewViewConfig.js | 63 +------------------ .../Components/View/ViewNativeComponent.js | 6 +- .../verifyComponentAttributeEquivalence.js | 2 +- 3 files changed, 8 insertions(+), 63 deletions(-) diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 942a269790f1f5..d723f2797e7de1 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -10,12 +10,12 @@ 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); - const ReactNativeViewConfig = { uiViewClassName: 'RCTView', + baseModuleName: null, + Manager: 'ViewManager', Commands: {}, + Constants: {}, bubblingEventTypes: { topBlur: { phasedRegistrationNames: { @@ -53,12 +53,6 @@ const ReactNativeViewConfig = { captured: 'onPressCapture', }, }, - topSelect: { - phasedRegistrationNames: { - bubbled: 'onSelect', - captured: 'onSelectCapture', - }, - }, topSubmitEditing: { phasedRegistrationNames: { bubbled: 'onSubmitEditing', @@ -91,9 +85,6 @@ const ReactNativeViewConfig = { }, }, directEventTypes: { - performAction: { - registrationName: 'onAccessibilityAction', - }, topAccessibilityAction: { registrationName: 'onAccessibilityAction', }, @@ -103,48 +94,12 @@ const ReactNativeViewConfig = { topAccessibilityTap: { registrationName: 'onAccessibilityTap', }, - topClick: { - registrationName: 'onClick', - }, - topContentSizeChange: { - registrationName: 'onContentSizeChange', - }, topLayout: { registrationName: 'onLayout', }, - topLoadingError: { - registrationName: 'onLoadingError', - }, - topLoadingFinish: { - registrationName: 'onLoadingFinish', - }, - topLoadingStart: { - registrationName: 'onLoadingStart', - }, topMagicTap: { registrationName: 'onMagicTap', }, - topMessage: { - registrationName: 'onMessage', - }, - topMomentumScrollBegin: { - registrationName: 'onMomentumScrollBegin', - }, - topMomentumScrollEnd: { - registrationName: 'onMomentumScrollEnd', - }, - topScroll: { - registrationName: 'onScroll', - }, - topScrollBeginDrag: { - registrationName: 'onScrollBeginDrag', - }, - topScrollEndDrag: { - registrationName: 'onScrollEndDrag', - }, - topSelectionChange: { - registrationName: 'onSelectionChange', - }, }, validAttributes: { accessibilityActions: true, @@ -201,7 +156,6 @@ const ReactNativeViewConfig = { flexGrow: true, flexShrink: true, flexWrap: true, - hasTVPreferredFocus: true, height: true, hitSlop: {diff: (require('../../Utilities/differ/insetsDiffer'): any)}, importantForAccessibility: true, @@ -220,15 +174,8 @@ const ReactNativeViewConfig = { maxWidth: true, minHeight: true, minWidth: true, - nativeBackgroundAndroid: true, - nativeForegroundAndroid: true, nativeID: true, needsOffscreenAlphaCompositing: true, - nextFocusDown: true, - nextFocusForward: true, - nextFocusLeft: true, - nextFocusRight: true, - nextFocusUp: true, onAccessibilityAction: true, onAccessibilityEscape: true, onAccessibilityTap: true, @@ -379,8 +326,4 @@ const ReactNativeViewConfig = { }, }; -verifyComponentAttributeEquivalence('RCTView', ReactNativeViewConfig); - -ReactNativeViewConfigRegistry.register('RCTView', () => ReactNativeViewConfig); - module.exports = ReactNativeViewConfig; diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index aa7ea2b502141d..21e57c8a437ab5 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -12,10 +12,12 @@ const ReactNative = require('../../Renderer/shims/ReactNative'); +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + import type {ViewProps} from './ViewPropTypes'; type ViewNativeComponentType = Class>; -require('ReactNativeViewViewConfig'); +const NativeViewComponent = requireNativeComponent('RCTView'); -module.exports = (('RCTView': any): ViewNativeComponentType); +module.exports = ((NativeViewComponent: any): ViewNativeComponentType); diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index 63c66445a159c3..296b7837cbd7af 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -14,7 +14,7 @@ const getNativeComponentAttributes = require('../ReactNative/getNativeComponentA import type {ReactNativeBaseComponentViewConfig} from '../Renderer/shims/ReactNativeTypes'; -const IGNORED_KEYS = ['transform', 'hitSlop']; +const IGNORED_KEYS = ['transform']; /** * The purpose of this function is to validate that the view config that * native exposes for a given view manager is the same as the view config From 12b735a378fe8b09905c4b5ec498fcd1356fd06d Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 28 May 2019 17:23:16 -0700 Subject: [PATCH 005/330] Create structure of mapbuffer project Summary: Create structure of C++ side of mapbuffer project Reviewed By: shergin Differential Revision: D15529650 fbshipit-source-id: b563d3fbcfddcf46802ccb202e372233baad123d --- ReactCommon/fabric/mapbuffer/BUCK | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 ReactCommon/fabric/mapbuffer/BUCK diff --git a/ReactCommon/fabric/mapbuffer/BUCK b/ReactCommon/fabric/mapbuffer/BUCK new file mode 100644 index 00000000000000..c7029191c58da0 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/BUCK @@ -0,0 +1,66 @@ +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "fb_xplat_cxx_test", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) + +rn_xplat_cxx_library( + name = "mapbuffer", + srcs = glob( + ["**/*.cpp"], + exclude = glob(["tests/**/*.cpp"]), + ), + headers = glob( + ["**/*.h"], + exclude = glob(["tests/**/*.h"]), + ), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ], + prefix = "react", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + force_static = True, + macosx_tests_override = [], + platforms = (ANDROID), + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + ], + tests = [":tests"], + visibility = ["PUBLIC"], + deps = [ + "fbsource//xplat/fbsystrace:fbsystrace", + "fbsource//xplat/folly:headers_only", + "fbsource//xplat/folly:memory", + "fbsource//xplat/third-party/glog:glog", + react_native_xplat_target("utils:utils"), + ], +) + +fb_xplat_cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + contacts = ["oncall+react_native@xmail.facebook.com"], + platforms = (ANDROID), + deps = [ + "fbsource//xplat/folly:molly", + "fbsource//xplat/third-party/gmock:gtest", + ], +) From 382cb05ae6ccf96355d297bcf54055305c2a7bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 28 May 2019 19:06:14 -0700 Subject: [PATCH 006/330] Disable Android tests on Appveyor (#25066) Summary: Android is failing on Appveyor. Removing to regain signal on Windows. See https://ci.appveyor.com/project/Facebook/react-native/builds/24869333/job/tnif7yt4x0lfisju for an example. Pull Request resolved: https://github.com/facebook/react-native/pull/25066 Differential Revision: D15532362 Pulled By: hramos fbshipit-source-id: afb55297b385d8b7e497d9cf4d26420f9502df44 --- .appveyor/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor/config.yml b/.appveyor/config.yml index 545f955abeeaa2..a30baf7582a396 100644 --- a/.appveyor/config.yml +++ b/.appveyor/config.yml @@ -38,7 +38,7 @@ build_script: - yarn run flow-check-android - yarn run flow-check-ios - yarn run test - - gradlew.bat RNTester:android:app:assembleRelease + # - gradlew.bat RNTester:android:app:assembleRelease cache: - node_modules From 6677f405a2de0833286671bc308230ea1d574f82 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Wed, 29 May 2019 07:38:12 -0700 Subject: [PATCH 007/330] Deprecate `YGNode::setConfig` Summary: We want to phase out usage of config pointers on nodes. Setting configs is no longer needed, as a config is unly used during construction. Here we deprecate the setter, as it is no longer working as it used to (e.g. changing `useWebDefaults` after a node is constructed). Reviewed By: SidharthGuglani Differential Revision: D15416474 fbshipit-source-id: a2cc06cad0c5148cecce056ece5f141b3defe9a9 --- ReactCommon/yoga/yoga/YGMacros.h | 12 ++++++++++++ ReactCommon/yoga/yoga/YGNode.h | 3 ++- ReactCommon/yoga/yoga/Yoga.cpp | 12 +++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGMacros.h b/ReactCommon/yoga/yoga/YGMacros.h index 9c2989acb97670..badea8c3c3e489 100644 --- a/ReactCommon/yoga/yoga/YGMacros.h +++ b/ReactCommon/yoga/yoga/YGMacros.h @@ -30,3 +30,15 @@ #define YG_ENUM_BEGIN(name) enum name #define YG_ENUM_END(name) name #endif + +#ifdef __GNUC__ +#define YG_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define YG_DEPRECATED __declspec(deprecated) +#elif __cplusplus >= 201402L +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(deprecated) +#define YG_DEPRECATED [[deprecated]] +#endif +#endif +#endif diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index e5f1da3ca5ba78..1ef8014214b8e0 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -11,6 +11,7 @@ #include "YGConfig.h" #include "YGLayout.h" #include "YGStyle.h" +#include "YGMacros.h" #include "Yoga-internal.h" YGConfigRef YGConfigGetDefault(); @@ -272,7 +273,7 @@ struct YGNode { // TODO: rvalue override for setChildren - void setConfig(YGConfigRef config) { config_ = config; } + YG_DEPRECATED void setConfig(YGConfigRef config) { config_ = config; } void setDirty(bool isDirty); void setLayoutLastOwnerDirection(YGDirection direction); diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 93ad4148c79bdd..da24a549fd5247 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -253,7 +253,13 @@ static YGConfigRef YGConfigClone(const YGConfig& oldConfig) { } static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { - YGNodeRef node = YGNodeClone(oldNode); + auto config = YGConfigClone(*oldNode->getConfig()); + auto node = new YGNode{*oldNode, config}; + node->setOwner(nullptr); +#ifdef YG_ENABLE_EVENTS + Event::publish(node, {node->getConfig()}); +#endif + YGVector vec = YGVector(); vec.reserve(oldNode->getChildren().size()); YGNodeRef childNode = nullptr; @@ -264,10 +270,6 @@ static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { } node->setChildren(vec); - if (oldNode->getConfig() != nullptr) { - node->setConfig(YGConfigClone(*(oldNode->getConfig()))); - } - return node; } From 5a5c28a2cf6d4a2c6619041d9ab6cb7c72f8e1f2 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Wed, 29 May 2019 08:31:04 -0700 Subject: [PATCH 008/330] Temporarily bring back the "ToolbarAndroid" export for RN Summary: This unbreaks an issue at FB. Reviewed By: rickhanlonii Differential Revision: D15536623 fbshipit-source-id: 2d59542330d2b951908adf8b6c5c41ca4232bb07 --- Libraries/react-native/react-native-implementation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 1f4ab0051f9d58..66f1ce260e372e 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -335,6 +335,10 @@ module.exports = { get ViewPropTypes() { return require('DeprecatedViewPropTypes'); }, + // TODO(cpojer): Temporary fix for missing Toolbar + get ToolbarAndroid() { + return require('UnimplementedView'); + }, }; if (__DEV__) { From a3479c212a935468396872bf448777196784c880 Mon Sep 17 00:00:00 2001 From: Abhinandan Ramaprasath Date: Wed, 29 May 2019 13:01:45 -0700 Subject: [PATCH 009/330] Add specs for ModalManager (#24896) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for ModalManager Pull Request resolved: https://github.com/facebook/react-native/pull/24896 Reviewed By: rickhanlonii Differential Revision: D15471097 Pulled By: fkgozali fbshipit-source-id: 99671583ddc2a6fc32fd1bcf9a6e340ad93a27c2 --- Libraries/Modal/Modal.js | 7 +++---- Libraries/Modal/NativeModalManager.js | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 Libraries/Modal/NativeModalManager.js diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index e364ec0af7f74c..40c03122bb2c14 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -13,7 +13,7 @@ const AppContainer = require('../ReactNative/AppContainer'); const I18nManager = require('../ReactNative/I18nManager'); const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativeModalManager from './NativeModalManager'; const Platform = require('../Utilities/Platform'); const React = require('react'); const PropTypes = require('prop-types'); @@ -21,10 +21,9 @@ const StyleSheet = require('../StyleSheet/StyleSheet'); const View = require('../Components/View/View'); const RCTModalHostView = require('./RCTModalHostViewNativeComponent'); - const ModalEventEmitter = - Platform.OS === 'ios' && NativeModules.ModalManager - ? new NativeEventEmitter(NativeModules.ModalManager) + Platform.OS === 'ios' && NativeModalManager != null + ? new NativeEventEmitter(NativeModalManager) : null; import type EmitterSubscription from '../vendor/emitter/EmitterSubscription'; diff --git a/Libraries/Modal/NativeModalManager.js b/Libraries/Modal/NativeModalManager.js new file mode 100644 index 00000000000000..28bf3d9a548d89 --- /dev/null +++ b/Libraries/Modal/NativeModalManager.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.get('ModalManager'); From 71461cb3dd4ad40dbe4de656bfec4b1a614ffa95 Mon Sep 17 00:00:00 2001 From: michalchudziak Date: Wed, 29 May 2019 13:01:45 -0700 Subject: [PATCH 010/330] Add spec for AccessibilityManager (#24894) Summary: Part of https://github.com/facebook/react-native/issues/24875 ## Changelog [General] [Added] - Add TurboModule spec for AccessibilityManager Pull Request resolved: https://github.com/facebook/react-native/pull/24894 Reviewed By: rickhanlonii Differential Revision: D15471243 Pulled By: fkgozali fbshipit-source-id: 33f39d41d70da9380f29f2eb47e8c7682b323030 --- .../AccessibilityInfo.ios.js | 52 +++++++++++++++---- .../NativeAccessibilityManager.js | 45 ++++++++++++++++ 2 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js index c759491c62ea51..a804af6fd68dd0 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js @@ -10,12 +10,11 @@ 'use strict'; -const NativeModules = require('../../BatchedBridge/NativeModules'); +import NativeAccessibilityManager from './NativeAccessibilityManager'; + const Promise = require('../../Promise'); const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter'); -const AccessibilityManager = NativeModules.AccessibilityManager; - const CHANGE_EVENT_NAME = { announcementFinished: 'announcementFinished', boldTextChanged: 'boldTextChanged', @@ -59,7 +58,11 @@ const AccessibilityInfo = { */ isBoldTextEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentBoldTextState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentBoldTextState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -73,7 +76,11 @@ const AccessibilityInfo = { */ isGrayscaleEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentGrayscaleState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentGrayscaleState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -87,7 +94,11 @@ const AccessibilityInfo = { */ isInvertColorsEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentInvertColorsState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentInvertColorsState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -101,7 +112,11 @@ const AccessibilityInfo = { */ isReduceMotionEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentReduceMotionState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentReduceMotionState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -115,7 +130,14 @@ const AccessibilityInfo = { */ isReduceTransparencyEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentReduceTransparencyState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentReduceTransparencyState( + resolve, + reject, + ); + } else { + reject(reject); + } }); }, @@ -129,7 +151,11 @@ const AccessibilityInfo = { */ isScreenReaderEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentVoiceOverState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentVoiceOverState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -204,7 +230,9 @@ const AccessibilityInfo = { * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#setaccessibilityfocus */ setAccessibilityFocus: function(reactTag: number): void { - AccessibilityManager.setAccessibilityFocus(reactTag); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.setAccessibilityFocus(reactTag); + } }, /** @@ -213,7 +241,9 @@ const AccessibilityInfo = { * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#announceforaccessibility */ announceForAccessibility: function(announcement: string): void { - AccessibilityManager.announceForAccessibility(announcement); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.announceForAccessibility(announcement); + } }, /** diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js new file mode 100644 index 00000000000000..2e90cdf4f8c63b --- /dev/null +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js @@ -0,0 +1,45 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getCurrentBoldTextState: ( + onSuccess: (isBoldTextEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentGrayscaleState: ( + onSuccess: (isGrayscaleEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentInvertColorsState: ( + onSuccess: (isInvertColorsEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentReduceMotionState: ( + onSuccess: (isReduceMotionEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentReduceTransparencyState: ( + onSuccess: (isReduceTransparencyEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentVoiceOverState: ( + onSuccess: (isScreenReaderEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +setAccessibilityFocus: (reactTag: number) => void; + +announceForAccessibility: (announcement: string) => void; +} + +export default TurboModuleRegistry.get('AccessibilityManager'); From 40625ceabf8ced0497f7bdeb4c2ed6b659e3e05a Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 29 May 2019 13:23:04 -0700 Subject: [PATCH 011/330] Revert Slider and Activity indicator view configs Summary: Reverting the generated view configs due to a potential issue Reviewed By: mdvacca Differential Revision: D15539319 fbshipit-source-id: bddf923dcfda18bd074196f06610fea8bb4561b4 --- .../ActivityIndicatorViewNativeComponent.js | 6 +- .../ActivityIndicatorViewNativeViewConfig.js | 45 ----------- .../Slider/SliderNativeComponent.js | 4 +- .../Slider/SliderNativeViewConfig.js | 76 ------------------- .../viewconfigs/generate-view-configs-cli.js | 6 +- 5 files changed, 9 insertions(+), 128 deletions(-) delete mode 100644 Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js delete mode 100644 Libraries/Components/Slider/SliderNativeViewConfig.js diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js index 731b6f3fb27244..213f1d0e796a24 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js @@ -18,6 +18,8 @@ import type { import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + type NativeProps = $ReadOnly<{| ...ViewProps, @@ -61,4 +63,6 @@ type ActivityIndicatorNativeType = CodegenNativeComponent< Options, >; -module.exports = ((require('./ActivityIndicatorViewNativeViewConfig'): any): ActivityIndicatorNativeType); +module.exports = ((requireNativeComponent( + 'RCTActivityIndicatorView', +): any): ActivityIndicatorNativeType); diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js deleted file mode 100644 index 0e448d1d21f24e..00000000000000 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js +++ /dev/null @@ -1,45 +0,0 @@ - -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -'use strict'; - -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); - -const ActivityIndicatorViewViewConfig = { - uiViewClassName: 'RCTActivityIndicatorView', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, - hidesWhenStopped: true, - animating: true, - color: { process: require('processColor') }, - size: true, - }, -}; - -verifyComponentAttributeEquivalence('RCTActivityIndicatorView', ActivityIndicatorViewViewConfig); - -ReactNativeViewConfigRegistry.register( - 'RCTActivityIndicatorView', - () => ActivityIndicatorViewViewConfig, -); - -module.exports = 'RCTActivityIndicatorView'; // RCT prefix present for paper support diff --git a/Libraries/Components/Slider/SliderNativeComponent.js b/Libraries/Components/Slider/SliderNativeComponent.js index a100656c2702c3..d7d90e0cdab608 100644 --- a/Libraries/Components/Slider/SliderNativeComponent.js +++ b/Libraries/Components/Slider/SliderNativeComponent.js @@ -22,6 +22,8 @@ import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ImageSource} from '../../Image/ImageSource'; import type {ViewProps} from '../View/ViewPropTypes'; +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + type Event = $ReadOnly<{| value: Float, fromUser?: boolean, @@ -59,4 +61,4 @@ type Options = { type SliderType = CodegenNativeComponent<'Slider', NativeProps, Options>; -module.exports = ((require('SliderNativeViewConfig'): any): SliderType); +module.exports = ((requireNativeComponent('RCTSlider'): any): SliderType); diff --git a/Libraries/Components/Slider/SliderNativeViewConfig.js b/Libraries/Components/Slider/SliderNativeViewConfig.js deleted file mode 100644 index 92abe056836b21..00000000000000 --- a/Libraries/Components/Slider/SliderNativeViewConfig.js +++ /dev/null @@ -1,76 +0,0 @@ - -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -'use strict'; - -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); - -const SliderViewConfig = { - uiViewClassName: 'RCTSlider', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - - topChange: { - phasedRegistrationNames: { - captured: 'onChangeCapture', - bubbled: 'onChange', - }, - }, - - topValueChange: { - phasedRegistrationNames: { - captured: 'onValueChangeCapture', - bubbled: 'onValueChange', - }, - }, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - - topSlidingComplete: { - registrationName: 'onSlidingComplete', - }, - }, - - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, - disabled: true, - enabled: true, - maximumTrackImage: { process: require('resolveAssetSource') }, - maximumTrackTintColor: { process: require('processColor') }, - maximumValue: true, - minimumTrackImage: { process: require('resolveAssetSource') }, - minimumTrackTintColor: { process: require('processColor') }, - minimumValue: true, - step: true, - testID: true, - thumbImage: { process: require('resolveAssetSource') }, - thumbTintColor: { process: require('processColor') }, - trackImage: { process: require('resolveAssetSource') }, - value: true, - onChange: true, - onValueChange: true, - onSlidingComplete: true, - }, -}; - -verifyComponentAttributeEquivalence('RCTSlider', SliderViewConfig); - -ReactNativeViewConfigRegistry.register( - 'RCTSlider', - () => SliderViewConfig, -); - -module.exports = 'RCTSlider'; // RCT prefix present for paper support diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index 8e73febfc260c6..68fc84cb1f80eb 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -23,11 +23,7 @@ const yargv = yargs.strict().option('t', { const argv = yargv.argv; const fileList = argv._[0].split('\n'); -const CURRENT_VIEW_CONFIG_FILES = [ - 'SliderNativeComponent.js', - 'ActivityIndicatorViewNativeComponent.js', - 'PullToRefreshViewNativeComponent.js', -]; +const CURRENT_VIEW_CONFIG_FILES = []; generate( fileList.filter(fileName => From 96a50010242cc1b33644aaa98ebddaaacd486cb5 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Wed, 29 May 2019 16:30:40 -0700 Subject: [PATCH 012/330] Add spec for DeviceInfo module Summary: Adding flow types for DeviceInfo module and migrating our codebase over to using `DeviceInfo.getConstants()` Reviewed By: fkgozali Differential Revision: D14645744 fbshipit-source-id: e30a060c6dc92938cd1420ba11a1d837c79d1e32 --- Libraries/Utilities/DeviceInfo.js | 8 +--- Libraries/Utilities/Dimensions.js | 5 +- Libraries/Utilities/NativeDeviceInfo.js | 47 +++++++++++++++++++ .../Utilities/__tests__/DeviceInfo-test.js | 2 +- .../react-native-implementation.js | 2 +- .../SafeAreaView/SafeAreaViewExample.js | 2 +- jest/setup.js | 30 +++++++----- 7 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 Libraries/Utilities/NativeDeviceInfo.js diff --git a/Libraries/Utilities/DeviceInfo.js b/Libraries/Utilities/DeviceInfo.js index 9757f2686e5a70..c3f59c5e88bced 100644 --- a/Libraries/Utilities/DeviceInfo.js +++ b/Libraries/Utilities/DeviceInfo.js @@ -10,10 +10,6 @@ 'use strict'; -const DeviceInfo = require('../BatchedBridge/NativeModules').DeviceInfo; +import NativeDeviceInfo from './NativeDeviceInfo'; -const invariant = require('invariant'); - -invariant(DeviceInfo, 'DeviceInfo native module is not installed correctly'); - -module.exports = DeviceInfo; +module.exports = NativeDeviceInfo; diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js index 383dcc44c8ac5c..508f6b0403dae5 100644 --- a/Libraries/Utilities/Dimensions.js +++ b/Libraries/Utilities/Dimensions.js @@ -14,6 +14,8 @@ const EventEmitter = require('../vendor/emitter/EventEmitter'); const Platform = require('./Platform'); const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter'); +import NativeDeviceInfo from './NativeDeviceInfo'; + const invariant = require('invariant'); const eventEmitter = new EventEmitter(); @@ -128,8 +130,7 @@ let dims: ?{[key: string]: any} = global.nativeExtensions.DeviceInfo.Dimensions; let nativeExtensionsEnabled = true; if (!dims) { - const DeviceInfo = require('./DeviceInfo'); - dims = DeviceInfo.Dimensions; + dims = NativeDeviceInfo.getConstants().Dimensions; nativeExtensionsEnabled = false; } diff --git a/Libraries/Utilities/NativeDeviceInfo.js b/Libraries/Utilities/NativeDeviceInfo.js new file mode 100644 index 00000000000000..dd905806547bff --- /dev/null +++ b/Libraries/Utilities/NativeDeviceInfo.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +type DisplayMetricsAndroid = {| + width: number, + height: number, + scale: number, + fontScale: number, + densityDpi: number, +|}; + +type DisplayMetricsIOS = {| + width: number, + height: number, + scale: number, + fontScale: number, +|}; + +export interface Spec extends TurboModule { + +getConstants: () => {| + +Dimensions: { + window?: DisplayMetricsIOS, + screen?: DisplayMetricsIOS, + windowPhysicalPixels?: DisplayMetricsAndroid, + screenPhysicalPixels?: DisplayMetricsAndroid, + }, + +isIPhoneX_deprecated?: boolean, + |}; +} + +const NativeModule = TurboModuleRegistry.getEnforcing('DeviceInfo'); + +const NativeDeviceInfo = NativeModule; + +export default NativeDeviceInfo; diff --git a/Libraries/Utilities/__tests__/DeviceInfo-test.js b/Libraries/Utilities/__tests__/DeviceInfo-test.js index 049feb571d7549..8cc9c224461aeb 100644 --- a/Libraries/Utilities/__tests__/DeviceInfo-test.js +++ b/Libraries/Utilities/__tests__/DeviceInfo-test.js @@ -14,6 +14,6 @@ describe('DeviceInfo', () => { const DeviceInfo = require('../DeviceInfo'); it('should give device info', () => { - expect(DeviceInfo).toHaveProperty('Dimensions'); + expect(DeviceInfo.getConstants()).toHaveProperty('Dimensions'); }); }); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 66f1ce260e372e..0b9f07b6aa9ec2 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -206,7 +206,7 @@ module.exports = { return require('DatePickerAndroid'); }, get DeviceInfo() { - return require('DeviceInfo'); + return require('NativeDeviceInfo').default; }, get Dimensions() { return require('Dimensions'); diff --git a/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js b/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js index 287c19bbfdf604..d92acd76f19c03 100644 --- a/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js +++ b/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js @@ -87,7 +87,7 @@ class IsIPhoneXExample extends React.Component<{}> { Is this an iPhone X:{' '} - {DeviceInfo.isIPhoneX_deprecated + {DeviceInfo.getConstants().isIPhoneX_deprecated ? 'Yeah!' : 'Nope. (Or `isIPhoneX_deprecated` was already removed.)'} diff --git a/jest/setup.js b/jest/setup.js index 3a2eb77bd2f05b..e03244ed5d982b 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -153,19 +153,23 @@ const mockNativeModules = { queryData: jest.fn(), }, DeviceInfo: { - Dimensions: { - window: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, - }, - screen: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, - }, + getConstants() { + return { + Dimensions: { + window: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, + screen: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, + }, + }; }, }, FacebookSDK: { From e923a2fa684b136bf7c0c54f3fa2acacb88d31a4 Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Wed, 29 May 2019 18:07:56 -0700 Subject: [PATCH 013/330] Use libdefs for fbjs instead of types from node_modules Summary: When code depends on a module from fbjs, its types come from the node_modules directory. This is problematic when Flow is deployed, since we can't codemod the parts that come from node_modules. Reviewed By: dsainati1 Differential Revision: D15547035 fbshipit-source-id: 8794a32e0f5786bcdd80eab98344d4bc623fb674 --- Libraries/Sample/Sample.android.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js index 2b30b41d7defa4..3924e178310770 100644 --- a/Libraries/Sample/Sample.android.js +++ b/Libraries/Sample/Sample.android.js @@ -16,6 +16,7 @@ const warning = require('fbjs/lib/warning'); const Sample = { test: function() { + // $FlowFixMe warning expects a condition warning('Not yet implemented for Android.'); }, }; From 87b31bccdf23246339e6377f0c9e80ac827534ab Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Wed, 29 May 2019 18:07:56 -0700 Subject: [PATCH 014/330] @allow-large-files Deploy Flow v0.99.0 to xplat/js Reviewed By: dsainati1 Differential Revision: D15541620 fbshipit-source-id: e19795e13d47dca58c5603b308b7cd60ba67ef86 --- .flowconfig | 2 +- .flowconfig.android | 2 +- Libraries/Alert/Alert.js | 1 - .../DrawerAndroid/__tests__/DrawerAndroid-test.js | 4 +++- .../Components/Picker/PickerAndroid.android.js | 2 -- .../__tests__/ProgressBarAndroid-test.js | 4 +++- Libraries/Image/ImageSource.js | 1 - Libraries/Lists/SectionList.js | 6 +++--- Libraries/Sample/Sample.android.js | 4 +++- RNTester/js/RNTesterApp.android.js | 2 -- RNTester/js/examples/Picker/PickerExample.js | 3 +++ RNTester/js/utils/RNTesterList.android.js | 14 -------------- RNTester/js/utils/RNTesterNavigationReducer.js | 1 - RNTester/js/utils/URIActionMap.js | 1 - package.json | 2 +- .../cli/viewconfigs/generate-view-configs-cli.js | 4 +++- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 18 files changed, 26 insertions(+), 37 deletions(-) diff --git a/.flowconfig b/.flowconfig index 16440a06e5521e..69e9a5aef1cdf7 100644 --- a/.flowconfig +++ b/.flowconfig @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.98.0 +^0.99.0 diff --git a/.flowconfig.android b/.flowconfig.android index 743e61c8437073..dce8cc3e8bda53 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.98.0 +^0.99.0 diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 63f5b31d4fe30c..c0afc6573bb73f 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -150,7 +150,6 @@ class Alert { }, (id, value) => { const cb = callbacks[id]; - // $FlowFixMe cb && cb(value); }, ); diff --git a/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js b/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js index e9747a088b26fe..514edf85cc4489 100644 --- a/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js +++ b/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js @@ -12,7 +12,9 @@ 'use strict'; const React = require('react'); -// $FlowFixMe +/* $FlowFixMe(>=0.99.0 site=react_native_ios_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ const DrawerLayoutAndroid = require('../DrawerLayoutAndroid.android'); const View = require('../../View/View'); diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js index d6aafd918add3d..744559b2807584 100644 --- a/Libraries/Components/Picker/PickerAndroid.android.js +++ b/Libraries/Components/Picker/PickerAndroid.android.js @@ -117,8 +117,6 @@ class PickerAndroid extends React.Component< item => item != null, ); const value = children[position].props.value; - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was - * found when making Flow check .android.js files. */ if (this.props.selectedValue !== value) { this.props.onValueChange(value, position); } diff --git a/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js b/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js index 9f479341b0658f..ccce645eb49aa5 100644 --- a/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js +++ b/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js @@ -12,7 +12,9 @@ 'use strict'; const React = require('react'); -// $FlowFixMe +/* $FlowFixMe(>=0.99.0 site=react_native_ios_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ const ProgressBarAndroid = require('../ProgressBarAndroid.android'); const render = require('../../../../jest/renderer'); diff --git a/Libraries/Image/ImageSource.js b/Libraries/Image/ImageSource.js index 0e03dc78c0f5d1..4607ef14223357 100644 --- a/Libraries/Image/ImageSource.js +++ b/Libraries/Image/ImageSource.js @@ -87,5 +87,4 @@ export type ImageURISource = $ReadOnly<{ // We have to export any because of an issue in Flow with objects that come from Relay: // https://fburl.com/8ljo5tmr // https://fb.facebook.com/groups/flow/permalink/1824103160971624/ -// $FlowFixMe T26861415 export type ImageSource = ImageURISource | number | Array; diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index 076fb0e29f66b9..f1bbe26bd4a808 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -303,9 +303,6 @@ class SectionList> extends React.PureComponent< render() { return ( - /* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.66 was deployed. To see the error delete this - * comment and run Flow. */ > extends React.PureComponent< _wrapperListRef: ?React.ElementRef; _captureRef = ref => { + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ this._wrapperListRef = ref; }; } diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js index 3924e178310770..3a7a25b51155c9 100644 --- a/Libraries/Sample/Sample.android.js +++ b/Libraries/Sample/Sample.android.js @@ -16,7 +16,9 @@ const warning = require('fbjs/lib/warning'); const Sample = { test: function() { - // $FlowFixMe warning expects a condition + /* $FlowFixMe(>=0.99.0 site=react_native_android_fb) This comment + * suppresses an error found when Flow v0.99 was deployed. To see the + * error, delete this comment and run Flow. */ warning('Not yet implemented for Android.'); }, }; diff --git a/RNTester/js/RNTesterApp.android.js b/RNTester/js/RNTesterApp.android.js index b87a9198b27430..a7c79047de9664 100644 --- a/RNTester/js/RNTesterApp.android.js +++ b/RNTester/js/RNTesterApp.android.js @@ -29,8 +29,6 @@ const { const RNTesterActions = require('./utils/RNTesterActions'); const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); const RNTesterExampleList = require('./components/RNTesterExampleList'); -/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found when - * making Flow check .android.js files. */ const RNTesterList = require('./utils/RNTesterList'); const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); const URIActionMap = require('./utils/URIActionMap'); diff --git a/RNTester/js/examples/Picker/PickerExample.js b/RNTester/js/examples/Picker/PickerExample.js index 417f9387cffc68..b9af4bb67e2f3a 100644 --- a/RNTester/js/examples/Picker/PickerExample.js +++ b/RNTester/js/examples/Picker/PickerExample.js @@ -167,6 +167,9 @@ exports.examples = [ title: 'Picker with no listener', render: function(): React.Element { return ( + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete + * this comment and run Flow. */ <> diff --git a/RNTester/js/utils/RNTesterList.android.js b/RNTester/js/utils/RNTesterList.android.js index cf9f10f78e7a91..929d0b78cea949 100644 --- a/RNTester/js/utils/RNTesterList.android.js +++ b/RNTester/js/utils/RNTesterList.android.js @@ -55,8 +55,6 @@ const ComponentExamples: Array = [ }, { key: 'ProgressBarAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/ProgressBarAndroid/ProgressBarAndroidExample'), }, { @@ -85,14 +83,10 @@ const ComponentExamples: Array = [ }, { key: 'TextExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/Text/TextExample'), }, { key: 'TextInputExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/TextInput/TextInputExample'), }, { @@ -105,8 +99,6 @@ const ComponentExamples: Array = [ }, { key: 'ViewPagerAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/ViewPagerAndroid/ViewPagerAndroidExample'), }, ]; @@ -118,8 +110,6 @@ const APIExamples: Array = [ }, { key: 'AccessibilityAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/Accessibility/AccessibilityAndroidExample'), }, { @@ -184,8 +174,6 @@ const APIExamples: Array = [ }, { key: 'PermissionsExampleAndroid', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/PermissionsAndroid/PermissionsExample'), }, { @@ -210,8 +198,6 @@ const APIExamples: Array = [ }, { key: 'ToastAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/ToastAndroid/ToastAndroidExample'), }, { diff --git a/RNTester/js/utils/RNTesterNavigationReducer.js b/RNTester/js/utils/RNTesterNavigationReducer.js index a7b68d6bc9b68d..b406eabcf3a660 100644 --- a/RNTester/js/utils/RNTesterNavigationReducer.js +++ b/RNTester/js/utils/RNTesterNavigationReducer.js @@ -10,7 +10,6 @@ 'use strict'; -// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS? const RNTesterList = require('./RNTesterList'); export type RNTesterNavigationState = { diff --git a/RNTester/js/utils/URIActionMap.js b/RNTester/js/utils/URIActionMap.js index 3dba73d27bf8ca..d03f40572a092a 100644 --- a/RNTester/js/utils/URIActionMap.js +++ b/RNTester/js/utils/URIActionMap.js @@ -12,7 +12,6 @@ const ReactNative = require('react-native'); const RNTesterActions = require('./RNTesterActions'); -// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS? const RNTesterList = require('./RNTesterList'); const {Alert} = ReactNative; diff --git a/package.json b/package.json index 38ae1245970930..ec40027e2ddc36 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "eslint-plugin-react-hooks": "^1.5.1", "eslint-plugin-react-native": "3.6.0", "eslint-plugin-relay": "1.3.0", - "flow-bin": "^0.98.0", + "flow-bin": "^0.99.0", "flow-remove-types": "1.2.3", "jest": "^24.7.1", "jest-junit": "^6.3.0", diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index 68fc84cb1f80eb..6603717369500f 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -31,6 +31,8 @@ generate( fileName.endsWith(supportedFileName), ), ), - // $FlowFixMe Type argv + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.99 was deployed. To see the error, delete this comment + * and run Flow. */ {test: argv.test, parser: 'flow'}, ); diff --git a/template/_flowconfig b/template/_flowconfig index 1319ea127818c3..2047ef0464540a 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -96,4 +96,4 @@ untyped-import untyped-type-import [version] -^0.98.0 +^0.99.0 diff --git a/yarn.lock b/yarn.lock index 000f16ca52c9c9..1db6f52c69c42d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3198,10 +3198,10 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" -flow-bin@^0.98.0: - version "0.98.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.98.0.tgz#3361a03682326a83a5f0a864749f4f7f0d826bce" - integrity sha512-vuiYjBVt82eYF+dEk9Zqa8hTSDvbhl/czxzFRLZm9/XHbJnYNMTwFoNFYAQT9IQ6ACNBIbwSTIfxroieuKja7g== +flow-bin@^0.99.0: + version "0.99.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.99.1.tgz#0d4f413ca84a3a95d0aa64214178684dd7c6a4c5" + integrity sha512-dipNwJlb4MsVt3IuDgPTymCNL4GFoq3pG+GbY6DmBbl0dJPWFSA383rCTmgbfFhoeJ1XCfYBan0BPryToSxiiQ== flow-parser@0.*: version "0.89.0" From 82fe1b05210fd703381c0a053bd3310bf12a4f1a Mon Sep 17 00:00:00 2001 From: Krzysztof Borowy Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 015/330] add spec for PermissionsAndroid (#24886) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for PermissionsAndroid Pull Request resolved: https://github.com/facebook/react-native/pull/24886 Reviewed By: RSNara Differential Revision: D15542996 Pulled By: fkgozali fbshipit-source-id: cab02d97e70d65347f63e891cff98c17adc1fdba --- .../NativePermissionsAndroid.js | 59 +++++++ .../PermissionsAndroid/PermissionsAndroid.js | 145 +++++++++++------- 2 files changed, 147 insertions(+), 57 deletions(-) create mode 100644 Libraries/PermissionsAndroid/NativePermissionsAndroid.js diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js new file mode 100644 index 00000000000000..fbac01fc8de583 --- /dev/null +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -0,0 +1,59 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +// TODO: Use proper enum types. +export type PermissionStatus = string; +export type PermissionType = string; +/* +export type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; +export type PermissionType = + | 'android.permission.READ_CALENDAR' + | 'android.permission.WRITE_CALENDAR' + | 'android.permission.CAMERA' + | 'android.permission.READ_CONTACTS' + | 'android.permission.WRITE_CONTACTS' + | 'android.permission.GET_ACCOUNTS' + | 'android.permission.ACCESS_FINE_LOCATION' + | 'android.permission.ACCESS_COARSE_LOCATION' + | 'android.permission.RECORD_AUDIO' + | 'android.permission.READ_PHONE_STATE' + | 'android.permission.CALL_PHONE' + | 'android.permission.READ_CALL_LOG' + | 'android.permission.WRITE_CALL_LOG' + | 'com.android.voicemail.permission.ADD_VOICEMAIL' + | 'android.permission.USE_SIP' + | 'android.permission.PROCESS_OUTGOING_CALLS' + | 'android.permission.BODY_SENSORS' + | 'android.permission.SEND_SMS' + | 'android.permission.RECEIVE_SMS' + | 'android.permission.READ_SMS' + | 'android.permission.RECEIVE_WAP_PUSH' + | 'android.permission.RECEIVE_MMS' + | 'android.permission.READ_EXTERNAL_STORAGE' + | 'android.permission.WRITE_EXTERNAL_STORAGE'; +*/ + +export interface Spec extends TurboModule { + +checkPermission: (permission: PermissionType) => Promise; + +requestPermission: (permission: PermissionType) => Promise; + +shouldShowRequestPermissionRationale: ( + permission: string, + ) => Promise; + +requestMultiplePermissions: ( + permissions: Array, + ) => Promise<{[permission: PermissionType]: PermissionStatus}>; +} + +export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 91522c89109012..1b414e71165a29 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -12,6 +12,13 @@ import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; const NativeModules = require('../BatchedBridge/NativeModules'); +const Platform = require('../Utilities/Platform'); +import NativePermissionsAndroid from './NativePermissionsAndroid'; + +import type { + PermissionStatus, + PermissionType, +} from './NativePermissionsAndroid'; export type Rationale = { title: string, @@ -21,7 +28,39 @@ export type Rationale = { buttonNeutral?: string, }; -type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; +const PERMISSION_REQUEST_RESULT = Object.freeze({ + GRANTED: 'granted', + DENIED: 'denied', + NEVER_ASK_AGAIN: 'never_ask_again', +}); + +const PERMISSIONS = Object.freeze({ + READ_CALENDAR: 'android.permission.READ_CALENDAR', + WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR', + CAMERA: 'android.permission.CAMERA', + READ_CONTACTS: 'android.permission.READ_CONTACTS', + WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS', + GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS', + ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION', + ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION', + RECORD_AUDIO: 'android.permission.RECORD_AUDIO', + READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE', + CALL_PHONE: 'android.permission.CALL_PHONE', + READ_CALL_LOG: 'android.permission.READ_CALL_LOG', + WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG', + ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL', + USE_SIP: 'android.permission.USE_SIP', + PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS', + BODY_SENSORS: 'android.permission.BODY_SENSORS', + SEND_SMS: 'android.permission.SEND_SMS', + RECEIVE_SMS: 'android.permission.RECEIVE_SMS', + READ_SMS: 'android.permission.READ_SMS', + RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH', + RECEIVE_MMS: 'android.permission.RECEIVE_MMS', + READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE', + WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE', +}); + /** * `PermissionsAndroid` provides access to Android M's new permissions model. * @@ -29,46 +68,8 @@ type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; */ class PermissionsAndroid { - PERMISSIONS: Object; - RESULTS: Object; - - constructor() { - /** - * A list of specified "dangerous" permissions that require prompting the user - */ - this.PERMISSIONS = { - READ_CALENDAR: 'android.permission.READ_CALENDAR', - WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR', - CAMERA: 'android.permission.CAMERA', - READ_CONTACTS: 'android.permission.READ_CONTACTS', - WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS', - GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS', - ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION', - ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION', - RECORD_AUDIO: 'android.permission.RECORD_AUDIO', - READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE', - CALL_PHONE: 'android.permission.CALL_PHONE', - READ_CALL_LOG: 'android.permission.READ_CALL_LOG', - WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG', - ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL', - USE_SIP: 'android.permission.USE_SIP', - PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS', - BODY_SENSORS: 'android.permission.BODY_SENSORS', - SEND_SMS: 'android.permission.SEND_SMS', - RECEIVE_SMS: 'android.permission.RECEIVE_SMS', - READ_SMS: 'android.permission.READ_SMS', - RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH', - RECEIVE_MMS: 'android.permission.RECEIVE_MMS', - READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE', - WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE', - }; - - this.RESULTS = { - GRANTED: 'granted', - DENIED: 'denied', - NEVER_ASK_AGAIN: 'never_ask_again', - }; - } + PERMISSIONS = PERMISSIONS; + RESULTS = PERMISSION_REQUEST_RESULT; /** * DEPRECATED - use check @@ -78,11 +79,18 @@ class PermissionsAndroid { * * @deprecated */ - checkPermission(permission: string): Promise { + checkPermission(permission: PermissionType): Promise { console.warn( '"PermissionsAndroid.checkPermission" is deprecated. Use "PermissionsAndroid.check" instead', ); - return NativeModules.PermissionsAndroid.checkPermission(permission); + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + + return NativePermissionsAndroid.checkPermission(permission); } /** @@ -91,8 +99,14 @@ class PermissionsAndroid { * * See https://facebook.github.io/react-native/docs/permissionsandroid.html#check */ - check(permission: string): Promise { - return NativeModules.PermissionsAndroid.checkPermission(permission); + check(permission: PermissionType): Promise { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + return NativePermissionsAndroid.checkPermission(permission); } /** @@ -110,12 +124,19 @@ class PermissionsAndroid { * @deprecated */ async requestPermission( - permission: string, + permission: PermissionType, rationale?: Rationale, ): Promise { console.warn( '"PermissionsAndroid.requestPermission" is deprecated. Use "PermissionsAndroid.request" instead', ); + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + const response = await this.request(permission, rationale); return response === this.RESULTS.GRANTED; } @@ -127,11 +148,18 @@ class PermissionsAndroid { * See https://facebook.github.io/react-native/docs/permissionsandroid.html#request */ async request( - permission: string, + permission: PermissionType, rationale?: Rationale, ): Promise { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(this.RESULTS.DENIED); + } + if (rationale) { - const shouldShowRationale = await NativeModules.PermissionsAndroid.shouldShowRequestPermissionRationale( + const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, ); @@ -144,14 +172,12 @@ class PermissionsAndroid { options, () => reject(new Error('Error showing rationale')), () => - resolve( - NativeModules.PermissionsAndroid.requestPermission(permission), - ), + resolve(NativePermissionsAndroid.requestPermission(permission)), ); }); } } - return NativeModules.PermissionsAndroid.requestPermission(permission); + return NativePermissionsAndroid.requestPermission(permission); } /** @@ -162,11 +188,16 @@ class PermissionsAndroid { * See https://facebook.github.io/react-native/docs/permissionsandroid.html#requestmultiple */ requestMultiple( - permissions: Array, - ): Promise<{[permission: string]: PermissionStatus}> { - return NativeModules.PermissionsAndroid.requestMultiplePermissions( - permissions, - ); + permissions: Array, + ): Promise<{[permission: PermissionType]: PermissionStatus}> { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve({}); + } + + return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From aaa4127332ae858ae5d3ea40d1fcfbbe9c3ef5b0 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 016/330] Add spec for Settings (#24879) Summary: part of #24875. I again, am not completely sure how the call site here works- appears settings can be directly accessed? ## Changelog [General] [Added] - Add TM spec for Settings Pull Request resolved: https://github.com/facebook/react-native/pull/24879 Reviewed By: RSNara Differential Revision: D15543012 Pulled By: fkgozali fbshipit-source-id: a1df3096a2fc5fe8e65d0ed2398912530bd3911a --- Libraries/Settings/NativeSettingsManager.js | 24 +++++++++++++++++++++ Libraries/Settings/Settings.ios.js | 8 +++---- 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 Libraries/Settings/NativeSettingsManager.js diff --git a/Libraries/Settings/NativeSettingsManager.js b/Libraries/Settings/NativeSettingsManager.js new file mode 100644 index 00000000000000..fd050c996b7cf4 --- /dev/null +++ b/Libraries/Settings/NativeSettingsManager.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + settings: Object, + |}; + +setValues: (values: Object) => void; + +deleteValues: (values: Array) => void; +} + +export default TurboModuleRegistry.getEnforcing('SettingsManager'); diff --git a/Libraries/Settings/Settings.ios.js b/Libraries/Settings/Settings.ios.js index 4084364721ec3e..c802759f764d1b 100644 --- a/Libraries/Settings/Settings.ios.js +++ b/Libraries/Settings/Settings.ios.js @@ -11,15 +11,15 @@ 'use strict'; const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter'); -const RCTSettingsManager = require('../BatchedBridge/NativeModules') - .SettingsManager; +import NativeSettingsManager from './NativeSettingsManager'; const invariant = require('invariant'); const subscriptions: Array<{keys: Array, callback: ?Function}> = []; const Settings = { - _settings: RCTSettingsManager && RCTSettingsManager.settings, + _settings: + NativeSettingsManager && NativeSettingsManager.getConstants().settings, get(key: string): mixed { return this._settings[key]; @@ -27,7 +27,7 @@ const Settings = { set(settings: Object) { this._settings = Object.assign(this._settings, settings); - RCTSettingsManager.setValues(settings); + NativeSettingsManager.setValues(settings); }, watchKeys(keys: string | Array, callback: Function): number { From 08efb1d73b73073cb8509bd5fe0189189d31392c Mon Sep 17 00:00:00 2001 From: Wojteg1337 Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 017/330] Add spec for AndroidToast (#24888) Summary: part of #24875 ## Changelog [General] [Added] - Add TM spec for AndroidToast Pull Request resolved: https://github.com/facebook/react-native/pull/24888 Reviewed By: RSNara Differential Revision: D15543043 Pulled By: fkgozali fbshipit-source-id: 6636dd913f7c006704ead1aa92d37e42a4edf70e --- .../ToastAndroid/NativeToastAndroid.js | 39 +++++++++++++++++++ .../ToastAndroid/ToastAndroid.android.js | 21 +++++----- .../ToastAndroid/ToastAndroid.ios.js | 18 +++++++++ 3 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 Libraries/Components/ToastAndroid/NativeToastAndroid.js diff --git a/Libraries/Components/ToastAndroid/NativeToastAndroid.js b/Libraries/Components/ToastAndroid/NativeToastAndroid.js new file mode 100644 index 00000000000000..89e74438740986 --- /dev/null +++ b/Libraries/Components/ToastAndroid/NativeToastAndroid.js @@ -0,0 +1,39 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + SHORT: number, + LONG: number, + TOP: number, + BOTTOM: number, + CENTER: number, + |}; + +show: (message: string, duration: number) => void; + +showWithGravity: ( + message: string, + duration: number, + gravity: number, + ) => void; + +showWithGravityAndOffset: ( + message: string, + duration: number, + gravity: number, + xOffset: number, + yOffset: number, + ) => void; +} + +export default TurboModuleRegistry.getEnforcing('ToastAndroid'); diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.android.js b/Libraries/Components/ToastAndroid/ToastAndroid.android.js index 30207d30a9ce71..ff1db3cf90bf88 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.android.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.android.js @@ -9,9 +9,7 @@ */ 'use strict'; - -const RCTToastAndroid = require('../../BatchedBridge/NativeModules') - .ToastAndroid; +import NativeToastAndroid from './NativeToastAndroid'; /** * This exposes the native ToastAndroid module as a JS module. This has a function 'show' @@ -36,16 +34,15 @@ const RCTToastAndroid = require('../../BatchedBridge/NativeModules') const ToastAndroid = { // Toast duration constants - SHORT: RCTToastAndroid.SHORT, - LONG: RCTToastAndroid.LONG, - + SHORT: NativeToastAndroid.getConstants().SHORT, + LONG: NativeToastAndroid.getConstants().LONG, // Toast gravity constants - TOP: RCTToastAndroid.TOP, - BOTTOM: RCTToastAndroid.BOTTOM, - CENTER: RCTToastAndroid.CENTER, + TOP: NativeToastAndroid.getConstants().TOP, + BOTTOM: NativeToastAndroid.getConstants().BOTTOM, + CENTER: NativeToastAndroid.getConstants().CENTER, show: function(message: string, duration: number): void { - RCTToastAndroid.show(message, duration); + NativeToastAndroid.show(message, duration); }, showWithGravity: function( @@ -53,7 +50,7 @@ const ToastAndroid = { duration: number, gravity: number, ): void { - RCTToastAndroid.showWithGravity(message, duration, gravity); + NativeToastAndroid.showWithGravity(message, duration, gravity); }, showWithGravityAndOffset: function( @@ -63,7 +60,7 @@ const ToastAndroid = { xOffset: number, yOffset: number, ): void { - RCTToastAndroid.showWithGravityAndOffset( + NativeToastAndroid.showWithGravityAndOffset( message, duration, gravity, diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js index ed5fcf02f40116..d0528ff65dc35e 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js @@ -16,6 +16,24 @@ const ToastAndroid = { show: function(message: string, duration: number): void { warning(false, 'ToastAndroid is not supported on this platform.'); }, + + showWithGravity: function( + message: string, + duration: number, + gravity: number, + ): void { + warning(false, 'ToastAndroid is not supported on this platform.'); + }, + + showWithGravityAndOffset: function( + message: string, + duration: number, + gravity: number, + xOffset: number, + yOffset: number, + ): void { + warning(false, 'ToastAndroid is not supported on this platform.'); + }, }; module.exports = ToastAndroid; From e8037cb942bf7dab13cc7e18baee53db720411f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 018/330] Add spec for Networking (#24892) Summary: Part of #24875, adds a spec for Networking. Since `sendRequest` methods are different for both platforms, I had to create 2 spec files as Flow would merge their definitions even when I added `Platform.OS` check ## Changelog [General] [Added] - TM spec for Networking Pull Request resolved: https://github.com/facebook/react-native/pull/24892 Reviewed By: RSNara Differential Revision: D15543067 Pulled By: fkgozali fbshipit-source-id: 2b91114dfa45e7899bbb139656a30a6fd52e31db --- Libraries/Network/NativeNetworkingAndroid.js | 38 ++++++++++++++++++++ Libraries/Network/NativeNetworkingIOS.js | 38 ++++++++++++++++++++ Libraries/Network/RCTNetworking.android.js | 13 ++++--- Libraries/Network/RCTNetworking.ios.js | 15 ++++---- 4 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 Libraries/Network/NativeNetworkingAndroid.js create mode 100644 Libraries/Network/NativeNetworkingIOS.js diff --git a/Libraries/Network/NativeNetworkingAndroid.js b/Libraries/Network/NativeNetworkingAndroid.js new file mode 100644 index 00000000000000..6db46cef70f5e9 --- /dev/null +++ b/Libraries/Network/NativeNetworkingAndroid.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +type Header = [string, string]; + +export interface Spec extends TurboModule { + +sendRequest: ( + method: string, + url: string, + requestId: number, + headers: Array
, + data: Object, + responseType: Object, // TODO: Use stricter type. + useIncrementalUpdates: boolean, + timeout: number, + withCredentials: boolean, + ) => void; + +abortRequest: (requestId: number) => void; + +clearCookies: (callback: (result: boolean) => mixed) => void; + + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.getEnforcing('Networking'); diff --git a/Libraries/Network/NativeNetworkingIOS.js b/Libraries/Network/NativeNetworkingIOS.js new file mode 100644 index 00000000000000..f61b3520a0ea67 --- /dev/null +++ b/Libraries/Network/NativeNetworkingIOS.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +sendRequest: ( + query: {| + method: string, + url: string, + data: Object, + headers: Object, + responseType: Object, // TODO: Use stricter type. + incrementalUpdates: boolean, + timeout: number, + withCredentials: boolean, + |}, + callback: (requestId: number) => mixed, + ) => void; + +abortRequest: (requestId: number) => void; + +clearCookies: (callback: (result: boolean) => mixed) => void; + + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.getEnforcing('Networking'); diff --git a/Libraries/Network/RCTNetworking.android.js b/Libraries/Network/RCTNetworking.android.js index 89435e2714cf9a..c809b8dcdd3a18 100644 --- a/Libraries/Network/RCTNetworking.android.js +++ b/Libraries/Network/RCTNetworking.android.js @@ -13,8 +13,7 @@ // Do not require the native RCTNetworking module directly! Use this wrapper module instead. // It will add the necessary requestId, so that you don't have to generate it yourself. const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); -const RCTNetworkingNative = require('../BatchedBridge/NativeModules') - .Networking; +import NativeNetworkingAndroid from './NativeNetworkingAndroid'; const convertRequestBody = require('./convertRequestBody'); import type {RequestBody} from './convertRequestBody'; @@ -42,7 +41,7 @@ function generateRequestId(): number { */ class RCTNetworking extends NativeEventEmitter { constructor() { - super(RCTNetworkingNative); + super(NativeNetworkingAndroid); } sendRequest( @@ -54,7 +53,7 @@ class RCTNetworking extends NativeEventEmitter { responseType: 'text' | 'base64', incrementalUpdates: boolean, timeout: number, - callback: (requestId: number) => any, + callback: (requestId: number) => mixed, withCredentials: boolean, ) { const body = convertRequestBody(data); @@ -65,7 +64,7 @@ class RCTNetworking extends NativeEventEmitter { })); } const requestId = generateRequestId(); - RCTNetworkingNative.sendRequest( + NativeNetworkingAndroid.sendRequest( method, url, requestId, @@ -80,11 +79,11 @@ class RCTNetworking extends NativeEventEmitter { } abortRequest(requestId: number) { - RCTNetworkingNative.abortRequest(requestId); + NativeNetworkingAndroid.abortRequest(requestId); } clearCookies(callback: (result: boolean) => any) { - RCTNetworkingNative.clearCookies(callback); + NativeNetworkingAndroid.clearCookies(callback); } } diff --git a/Libraries/Network/RCTNetworking.ios.js b/Libraries/Network/RCTNetworking.ios.js index 6905142cbff471..62f4f26b7894b6 100644 --- a/Libraries/Network/RCTNetworking.ios.js +++ b/Libraries/Network/RCTNetworking.ios.js @@ -11,8 +11,7 @@ 'use strict'; const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); -const RCTNetworkingNative = require('../BatchedBridge/NativeModules') - .Networking; +import NativeNetworkingIOS from './NativeNetworkingIOS'; const convertRequestBody = require('./convertRequestBody'); import type {RequestBody} from './convertRequestBody'; @@ -21,7 +20,7 @@ import type {NativeResponseType} from './XMLHttpRequest'; class RCTNetworking extends NativeEventEmitter { constructor() { - super(RCTNetworkingNative); + super(NativeNetworkingIOS); } sendRequest( @@ -33,11 +32,11 @@ class RCTNetworking extends NativeEventEmitter { responseType: NativeResponseType, incrementalUpdates: boolean, timeout: number, - callback: (requestId: number) => any, + callback: (requestId: number) => mixed, withCredentials: boolean, ) { const body = convertRequestBody(data); - RCTNetworkingNative.sendRequest( + NativeNetworkingIOS.sendRequest( { method, url, @@ -53,11 +52,11 @@ class RCTNetworking extends NativeEventEmitter { } abortRequest(requestId: number) { - RCTNetworkingNative.abortRequest(requestId); + NativeNetworkingIOS.abortRequest(requestId); } - clearCookies(callback: (result: boolean) => any) { - RCTNetworkingNative.clearCookies(callback); + clearCookies(callback: (result: boolean) => mixed) { + NativeNetworkingIOS.clearCookies(callback); } } From 338298417f8077dee177057c57b38671b4ec8c75 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 30 May 2019 02:00:03 -0700 Subject: [PATCH 019/330] Timing: Fixes timer when app get into background (#24649) Summary: Related #23674, in that PR, we imported background timer support, but it's not sufficient, I think the reason that works is because it enable the `Background Modes` and do some background tasks, for the users who don't enable it, timer would pause immediately before goes into background. To fix it, we can mark a background task when goes into background, it can keep app active for minutes, try best to support timing when in background. cc. cpojer . ## Changelog [iOS] [Fixed] - Timing: Fixes timer when app get into background Pull Request resolved: https://github.com/facebook/react-native/pull/24649 Differential Revision: D15554451 Pulled By: cpojer fbshipit-source-id: a33f7afe6b63d1a4fefcb7098459aee0c09145da --- React/Modules/RCTTiming.m | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m index ef4ec94819e3eb..7568dff8a58a8f 100644 --- a/React/Modules/RCTTiming.m +++ b/React/Modules/RCTTiming.m @@ -97,6 +97,7 @@ @implementation RCTTiming NSTimer *_sleepTimer; BOOL _sendIdleEvents; BOOL _inBackground; + UIBackgroundTaskIdentifier _backgroundTaskIdentifier; } @synthesize bridge = _bridge; @@ -112,6 +113,7 @@ - (void)setBridge:(RCTBridge *)bridge _paused = YES; _timers = [NSMutableDictionary new]; _inBackground = NO; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; for (NSString *name in @[UIApplicationWillResignActiveNotification, UIApplicationDidEnterBackgroundNotification, @@ -135,10 +137,35 @@ - (void)setBridge:(RCTBridge *)bridge - (void)dealloc { + [self markEndOfBackgroundTaskIfNeeded]; [_sleepTimer invalidate]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } +- (void)markStartOfBackgroundTaskIfNeeded +{ + if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) { + __weak typeof(self) weakSelf = self; + // Marks the beginning of a new long-running background task. We can run the timer in the background. + _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ + typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + // Mark the end of background task + [strongSelf markEndOfBackgroundTaskIfNeeded]; + }]; + } +} + +- (void)markEndOfBackgroundTaskIfNeeded +{ + if (_backgroundTaskIdentifier != UIBackgroundTaskInvalid) { + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } +} + - (dispatch_queue_t)methodQueue { return RCTJSThread; @@ -163,6 +190,7 @@ - (void)appDidMoveToBackground - (void)appDidMoveToForeground { + [self markEndOfBackgroundTaskIfNeeded]; _inBackground = NO; [self startTimers]; } @@ -260,6 +288,7 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update } if (_inBackground) { if (timerCount) { + [self markStartOfBackgroundTaskIfNeeded]; [self scheduleSleepTimer:nextScheduledTarget]; } } else if (!_sendIdleEvents && timersToCall.count == 0) { @@ -338,6 +367,7 @@ - (void)timerDidFire } if (_inBackground) { + [self markStartOfBackgroundTaskIfNeeded]; [self scheduleSleepTimer:timer.target]; } else if (_paused) { if ([timer.target timeIntervalSinceNow] > kMinimumSleepInterval) { From 6d54423b788ba2f0ec5c7eda9b2ab3d66a5bd529 Mon Sep 17 00:00:00 2001 From: Johan-dutoit Date: Thu, 30 May 2019 02:51:49 -0700 Subject: [PATCH 020/330] Add a deprecation warning when importing ImagePickerIOS (#25074) Summary: Added a deprecation warning for the ImagePickerIOS, module as part of #23313. ## Changelog [General] [Deprecated] - ImagePickerIOS [was moved to community repo](https://github.com/react-native-community/react-native-image-picker-ios) Pull Request resolved: https://github.com/facebook/react-native/pull/25074 Differential Revision: D15554728 Pulled By: cpojer fbshipit-source-id: 867f4c1db64064fef7511d8ff3dc0a621281eb7b --- Libraries/react-native/react-native-implementation.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 0b9f07b6aa9ec2..727d8f3415cce5 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -221,6 +221,13 @@ module.exports = { return require('I18nManager'); }, get ImagePickerIOS() { + warnOnce( + 'imagePickerIOS-moved', + 'ImagePickerIOS has been extracted from react-native core and will be removed in a future release. ' + + "Please upgrade to use either '@react-native-community/react-native-image-picker' or 'expo-image-picker'. " + + "If you cannot upgrade to a different library, please install the deprecated '@react-native-community/image-picker-ios' package. " + + 'See https://github.com/react-native-community/react-native-image-picker-ios', + ); return require('ImagePickerIOS'); }, get InteractionManager() { From c83a89daa6a2a562f46a1805d48a17c18e7f3cb4 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 30 May 2019 04:49:00 -0700 Subject: [PATCH 021/330] Upgrade RN gesture handler to 1.1.1 Summary: React Native Gesture Handler used to eagerly initialize all of its exports and therefore required a bunch of things from React Native eagerly. When we remove things from RN via the Lean Core project, this leads to failures. I asked Krzysztof to make a patch release that lazily loads them instead: https://github.com/kmagiera/react-native-gesture-handler/commit/da658c2de2e7135871e27284d9c8c6d323c5d803 Reviewed By: rickhanlonii Differential Revision: D15554658 fbshipit-source-id: aa4b82e5a3c2c837d160da914f41756d26cd6c07 --- Libraries/react-native/react-native-implementation.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 727d8f3415cce5..dbe17f81de8d51 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -342,10 +342,6 @@ module.exports = { get ViewPropTypes() { return require('DeprecatedViewPropTypes'); }, - // TODO(cpojer): Temporary fix for missing Toolbar - get ToolbarAndroid() { - return require('UnimplementedView'); - }, }; if (__DEV__) { From d31e90648e03911f54abc2874d388df124d99c21 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 30 May 2019 06:48:11 -0700 Subject: [PATCH 022/330] Add deprecation messages for NetInfo and CameraRoll Summary: I simply removed them from RN but we should give an actionable error message for people who upgrade from older versions of RN and who may be using these old modules, at least in `__DEV__`. Reviewed By: rickhanlonii Differential Revision: D15554863 fbshipit-source-id: 1975d4773581258776d2586ae820677bb14488f6 --- .../react-native-implementation.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index dbe17f81de8d51..94aeecb53941e9 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -383,4 +383,30 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access NetInfo. + Object.defineProperty(module.exports, 'NetInfo', { + configurable: true, + get() { + invariant( + false, + 'NetInfo has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-netinfo' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-netinfo', + ); + }, + }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access CameraRoll. + Object.defineProperty(module.exports, 'CameraRoll', { + configurable: true, + get() { + invariant( + false, + 'CameraRoll has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-cameraroll' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-cameraroll', + ); + }, + }); } From 33ee6f8b99d423dbe8e604852232a63d5abe94d4 Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 30 May 2019 07:41:37 -0700 Subject: [PATCH 023/330] Add a lint rule to disallow Haste imports (#25058) Summary: This is an ESLint plugin that infers whether an import looks like a Haste module name. To keep the linter fast and simple, it does not look in the Haste map. Instead, it looks for uppercase characters in single-name import paths, since npm has disallowed uppercase letters in package names for a long time. There are some false negatives (e.g. "merge" is a Haste module and this linter rule would not pick it up) but those are about 1.1% of the module names in the RN repo, and unit tests and integration tests will fail anyway once Haste is turned off. You can disable the lint rule on varying granular levels with ESLint's normal disabling/enabling mechanisms. Also rewrote more Haste imports so that the linter passes (i.e. fixed lint errors as part of this PR). ## Changelog [General] [Changed] - Add a lint rule to disallow Haste imports Pull Request resolved: https://github.com/facebook/react-native/pull/25058 Differential Revision: D15515826 Pulled By: cpojer fbshipit-source-id: d58a3c30dfe0887f8a530e3393af4af5a1ec1cac --- .eslintrc | 8 ++ Libraries/Alert/NativeAlertManager.js | 4 +- .../Animated/src/NativeAnimatedModule.js | 4 +- .../__tests__/MessageQueue-test.js | 2 +- .../__tests__/NativeModules-test.js | 2 +- .../NativeAccessibilityManager.js | 4 +- .../PullToRefreshViewNativeViewConfig.js | 10 +-- .../ToastAndroid/NativeToastAndroid.js | 4 +- Libraries/Image/NativeImageEditor.js | 4 +- Libraries/Modal/NativeModalManager.js | 4 +- .../specs/NativeDialogManagerAndroid.js | 4 +- Libraries/Network/NativeNetworkingAndroid.js | 4 +- Libraries/Network/NativeNetworkingIOS.js | 4 +- .../NativePermissionsAndroid.js | 4 +- Libraries/Settings/NativeSettingsManager.js | 4 +- Libraries/Utilities/NativeDeviceInfo.js | 4 +- .../react-native-implementation.js | 4 +- .../androidTest/js/ScrollViewTestModule.js | 2 +- package.json | 1 + .../index.js | 1 + .../README.md | 21 ++++++ .../index.js | 12 +++ .../no-haste-imports.js | 73 +++++++++++++++++++ .../package.json | 11 +++ yarn.lock | 5 ++ 25 files changed, 167 insertions(+), 33 deletions(-) create mode 100644 packages/eslint-plugin-react-native-community/README.md create mode 100644 packages/eslint-plugin-react-native-community/index.js create mode 100644 packages/eslint-plugin-react-native-community/no-haste-imports.js create mode 100644 packages/eslint-plugin-react-native-community/package.json diff --git a/.eslintrc b/.eslintrc index d18f7eb8286127..9c36dc1804f899 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,6 +6,14 @@ ], "overrides": [ + { + "files": [ + "Libraries/**/*.js", + ], + rules: { + '@react-native-community/no-haste-imports': 2 + } + }, { "files": [ "**/__fixtures__/**/*.js", diff --git a/Libraries/Alert/NativeAlertManager.js b/Libraries/Alert/NativeAlertManager.js index 0a540cac72770f..16191e7e4721e9 100644 --- a/Libraries/Alert/NativeAlertManager.js +++ b/Libraries/Alert/NativeAlertManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export type Buttons = Array<{ text?: string, diff --git a/Libraries/Animated/src/NativeAnimatedModule.js b/Libraries/Animated/src/NativeAnimatedModule.js index b13d6f33191bc4..80ece9d69d04cf 100644 --- a/Libraries/Animated/src/NativeAnimatedModule.js +++ b/Libraries/Animated/src/NativeAnimatedModule.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; type EndResult = {finished: boolean}; type EndCallback = (result: EndResult) => void; diff --git a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js index f8568cae72d172..0c2db74b5266e5 100644 --- a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js +++ b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js @@ -33,7 +33,7 @@ describe('MessageQueue', function() { beforeEach(function() { jest.resetModules(); MessageQueue = require('../MessageQueue'); - MessageQueueTestModule = require('MessageQueueTestModule'); + MessageQueueTestModule = require('../__mocks__/MessageQueueTestModule'); queue = new MessageQueue(); queue.registerCallableModule( 'MessageQueueTestModule', diff --git a/Libraries/BatchedBridge/__tests__/NativeModules-test.js b/Libraries/BatchedBridge/__tests__/NativeModules-test.js index 6457385f233acb..3bc364694ed2ac 100644 --- a/Libraries/BatchedBridge/__tests__/NativeModules-test.js +++ b/Libraries/BatchedBridge/__tests__/NativeModules-test.js @@ -40,7 +40,7 @@ describe('MessageQueue', function() { beforeEach(function() { jest.resetModules(); - global.__fbBatchedBridgeConfig = require('MessageQueueTestConfig'); + global.__fbBatchedBridgeConfig = require('../__mocks__/MessageQueueTestConfig'); BatchedBridge = require('../BatchedBridge'); NativeModules = require('../NativeModules'); }); diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js index 2e90cdf4f8c63b..b0fe8dd1d7ed70 100644 --- a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getCurrentBoldTextState: ( diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js index 27a1071076e540..f76c8e02dd2140 100644 --- a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js @@ -10,9 +10,9 @@ 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const ReactNativeViewConfigRegistry = require('../../Renderer/shims/ReactNativeViewConfigRegistry'); +const ReactNativeViewViewConfig = require('../View/ReactNativeViewViewConfig'); +const verifyComponentAttributeEquivalence = require('../../Utilities/verifyComponentAttributeEquivalence'); const PullToRefreshViewViewConfig = { uiViewClassName: 'PullToRefreshView', @@ -35,8 +35,8 @@ const PullToRefreshViewViewConfig = { validAttributes: { ...ReactNativeViewViewConfig.validAttributes, - tintColor: { process: require('processColor') }, - titleColor: { process: require('processColor') }, + tintColor: { process: require('../../StyleSheet/processColor') }, + titleColor: { process: require('../../StyleSheet/processColor') }, title: true, refreshing: true, onRefresh: true, diff --git a/Libraries/Components/ToastAndroid/NativeToastAndroid.js b/Libraries/Components/ToastAndroid/NativeToastAndroid.js index 89e74438740986..079a7d0112bcfd 100644 --- a/Libraries/Components/ToastAndroid/NativeToastAndroid.js +++ b/Libraries/Components/ToastAndroid/NativeToastAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {| diff --git a/Libraries/Image/NativeImageEditor.js b/Libraries/Image/NativeImageEditor.js index 4f4da0b5388b67..e208cb47b6df1c 100644 --- a/Libraries/Image/NativeImageEditor.js +++ b/Libraries/Image/NativeImageEditor.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +cropImage: ( diff --git a/Libraries/Modal/NativeModalManager.js b/Libraries/Modal/NativeModalManager.js index 28bf3d9a548d89..d293caf68f45c3 100644 --- a/Libraries/Modal/NativeModalManager.js +++ b/Libraries/Modal/NativeModalManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { // RCTEventEmitter diff --git a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js index 1ffb71c8ce8260..d1e1f9a7c83962 100644 --- a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js +++ b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; /* 'buttonClicked' | 'dismissed' */ type DialogAction = string; diff --git a/Libraries/Network/NativeNetworkingAndroid.js b/Libraries/Network/NativeNetworkingAndroid.js index 6db46cef70f5e9..06ccdf29fa154e 100644 --- a/Libraries/Network/NativeNetworkingAndroid.js +++ b/Libraries/Network/NativeNetworkingAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type Header = [string, string]; diff --git a/Libraries/Network/NativeNetworkingIOS.js b/Libraries/Network/NativeNetworkingIOS.js index f61b3520a0ea67..5c685de7845743 100644 --- a/Libraries/Network/NativeNetworkingIOS.js +++ b/Libraries/Network/NativeNetworkingIOS.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +sendRequest: ( diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index fbac01fc8de583..025f9af18419b1 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; // TODO: Use proper enum types. export type PermissionStatus = string; diff --git a/Libraries/Settings/NativeSettingsManager.js b/Libraries/Settings/NativeSettingsManager.js index fd050c996b7cf4..19de825248cdb9 100644 --- a/Libraries/Settings/NativeSettingsManager.js +++ b/Libraries/Settings/NativeSettingsManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {| diff --git a/Libraries/Utilities/NativeDeviceInfo.js b/Libraries/Utilities/NativeDeviceInfo.js index dd905806547bff..8e0b785a6fbc4f 100644 --- a/Libraries/Utilities/NativeDeviceInfo.js +++ b/Libraries/Utilities/NativeDeviceInfo.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type DisplayMetricsAndroid = {| width: number, diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 94aeecb53941e9..8e0a72c5ce0858 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -10,8 +10,10 @@ 'use strict'; +/* eslint-disable @react-native-community/no-haste-imports */ + const invariant = require('invariant'); -const warnOnce = require('warnOnce'); +const warnOnce = require('../Utilities/warnOnce'); // Export React, plus some native additions. module.exports = { diff --git a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js index 5da2b7686caa9c..3e097245800083 100644 --- a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js +++ b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js @@ -25,7 +25,7 @@ const {ScrollListener} = NativeModules; const NUM_ITEMS = 100; -import type {PressEvent} from 'CoreEventTypes'; +import type {PressEvent} from 'react-native/Libraries/Types/CoreEventTypes'; // Shared by integration tests for ScrollView and HorizontalScrollView diff --git a/package.json b/package.json index ec40027e2ddc36..d9bbd3257e2a31 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "devDependencies": { "@babel/core": "^7.0.0", "@babel/generator": "^7.0.0", + "@react-native-community/eslint-plugin": "1.0.0", "@reactions/component": "^2.0.2", "async": "^2.4.0", "babel-eslint": "10.0.1", diff --git a/packages/eslint-config-react-native-community/index.js b/packages/eslint-config-react-native-community/index.js index d1cfc6948713e2..8691452b8fab27 100644 --- a/packages/eslint-config-react-native-community/index.js +++ b/packages/eslint-config-react-native-community/index.js @@ -22,6 +22,7 @@ module.exports = { 'react', 'react-hooks', 'react-native', + '@react-native-community', 'jest', ], diff --git a/packages/eslint-plugin-react-native-community/README.md b/packages/eslint-plugin-react-native-community/README.md new file mode 100644 index 00000000000000..262c7e92171884 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/README.md @@ -0,0 +1,21 @@ +# eslint-plugin-react-native-community + +This plugin is intended to be used in `@react-native-community/eslint-plugin`. You probably want to install that package instead. + +## Installation + +``` +yarn add --dev eslint @react-native-community/eslint-plugin +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +## Usage + +Add to your eslint config (`.eslintrc`, or `eslintConfig` field in `package.json`): + +```json +{ + "plugins": ["@react-native-community"] +} +``` diff --git a/packages/eslint-plugin-react-native-community/index.js b/packages/eslint-plugin-react-native-community/index.js new file mode 100644 index 00000000000000..f0165057500822 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/index.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +exports.rules = { + 'no-haste-imports': require('./no-haste-imports'), +}; diff --git a/packages/eslint-plugin-react-native-community/no-haste-imports.js b/packages/eslint-plugin-react-native-community/no-haste-imports.js new file mode 100644 index 00000000000000..5282c6950ec2d6 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/no-haste-imports.js @@ -0,0 +1,73 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +module.exports = { + meta: { + type: 'problem', + docs: { + description: + 'disallow Haste module names in import statements and require calls', + }, + schema: [], + }, + + create(context) { + return { + ImportDeclaration(node) { + checkImportForHaste(context, node.source.value, node.source); + }, + CallExpression(node) { + if (isStaticRequireCall(node)) { + const [firstArgument] = node.arguments; + checkImportForHaste(context, firstArgument.value, firstArgument); + } + }, + }; + }, +}; + +function checkImportForHaste(context, importPath, node) { + if (isLikelyHasteModuleName(importPath)) { + context.report({ + node, + message: `"${importPath}" appears to be a Haste module name. Use path-based imports instead.`, + }); + } +} + +function isLikelyHasteModuleName(importPath) { + // Our heuristic assumes an import path is a Haste module name if it is not a + // path and doesn't appear to be an npm package. For several years, npm has + // disallowed uppercase characters in package names. + // + // This heuristic has a ~1% false negative rate for the filenames in React + // Native, which is acceptable since the linter will not complain wrongly and + // the rate is so low. False negatives that slip through will be caught by + // tests with Haste disabled. + return ( + // Exclude relative paths + !importPath.startsWith('.') && + // Exclude package-internal paths and scoped packages + !importPath.includes('/') && + // Include camelCase and UpperCamelCase + /[A-Z]/.test(importPath) + ); +} + +function isStaticRequireCall(node) { + return ( + node && + node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'require' && + node.arguments.length === 1 && + node.arguments[0].type === 'Literal' && + typeof node.arguments[0].value === 'string' + ); +} diff --git a/packages/eslint-plugin-react-native-community/package.json b/packages/eslint-plugin-react-native-community/package.json new file mode 100644 index 00000000000000..5a6c28f26d0281 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/package.json @@ -0,0 +1,11 @@ +{ + "name": "@react-native-community/eslint-plugin", + "version": "1.0.0", + "description": "ESLint rules for @react-native-community/eslint-config", + "main": "index.js", + "repository": { + "type": "git", + "url": "git@github.com:facebook/react-native.git" + }, + "license": "MIT" +} diff --git a/yarn.lock b/yarn.lock index 1db6f52c69c42d..37f37f1218e584 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1160,6 +1160,11 @@ shell-quote "1.6.1" ws "^1.1.0" +"@react-native-community/eslint-plugin@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.0.0.tgz#ae9a430f2c5795debca491f15a989fce86ea75a0" + integrity sha512-GLhSN8dRt4lpixPQh+8prSCy6PYk/MT/mvji/ojAd5yshowDo6HFsimCSTD/uWAdjpUq91XK9tVdTNWfGRlKQA== + "@reactions/component@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@reactions/component/-/component-2.0.2.tgz#40f8c1c2c37baabe57a0c944edb9310dc1ec6642" From aac95b409b38200c3e2a357c5faf77cf8273cb32 Mon Sep 17 00:00:00 2001 From: Oleksandr Melnykov Date: Thu, 30 May 2019 10:32:51 -0700 Subject: [PATCH 024/330] Fix switch being stuck in intermidiate state on Android Summary: This diff fixes the bug of the switch component on Android being stuck in the middle when a user releases their finger whily dragging the thumb. When a user releases their finger while dragging the thumb, `setChecked` will be called and if `mAllowChange` is set to false, `super.setChecked` is never called. The supper method will actually make sure the thumb will be animated to the correct edge. Without calling the super method, the thumb might stay in the middle of the switch where a user released their finger. The fix had to be applied both to ReactSwitch and FbReactSwitchCompat. One more fix had to be made to FbReactSwitchCompat since D5884661 was applied to ReactSwitch, but not to FbReactSwitchCompat: if (mAllowChange && **isChecked() != checked**) { ... } Reviewed By: mdvacca Differential Revision: D15535611 fbshipit-source-id: 22ca1fe3fa993ae65cbd677bfae2208a02c368d4 --- .../com/facebook/react/views/switchview/ReactSwitch.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java index fc716387770c11..dbbffb4bd78607 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java @@ -37,6 +37,11 @@ public void setChecked(boolean checked) { mAllowChange = false; super.setChecked(checked); setTrackColor(checked); + } else { + // Even if mAllowChange is set to false or the checked value hasn't changed, we still must + // call the super method, since it will make sure the thumb is moved back to the correct edge. + // Without calling the super method, the thumb might stuck in the middle of the switch. + super.setChecked(isChecked()); } } From 2aca234dee6a4c1e710b93dce341528279797c34 Mon Sep 17 00:00:00 2001 From: Petter Hesselberg Date: Thu, 30 May 2019 11:05:56 -0700 Subject: [PATCH 025/330] Don't reference null android.ndkDirectory in build.gradle (#25088) Summary: If you (try to) build React Native for Android without having the NDK properly installed and referenced, you get the following error: >A problem occurred evaluating project ':ReactAndroid'. \> Cannot get property 'absolutePath' on null object This is not an overly helpful diagnostic. This PR results in this message instead: >ndk-build binary cannot be found, check if you've set $ANDROID_NDK environment variable correctly or if ndk.dir is setup in local.properties Fixes #25087 ## Changelog [Android] [Fixed] - Show proper error message instead of throwing a NullReferenceException if Gradle cannot find the NDK Pull Request resolved: https://github.com/facebook/react-native/pull/25088 Differential Revision: D15559271 Pulled By: cpojer fbshipit-source-id: 35c9a9321af4e4a34bf519144ada48884b48352d --- ReactAndroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 8ac94f45161c29..6e44769892cbbc 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -193,7 +193,7 @@ def findNdkBuildFullPath() { def ndkDir = android.hasProperty("plugin") ? android.plugin.ndkFolder : plugins.getPlugin("com.android.library").hasProperty("sdkHandler") ? plugins.getPlugin("com.android.library").sdkHandler.getNdkFolder() : - android.ndkDirectory.absolutePath + android.ndkDirectory ? android.ndkDirectory.absolutePath : null if (ndkDir) { return new File(ndkDir, getNdkBuildName()).getAbsolutePath() } From 49f7e31ea36d35eb9197a130c3163cc5c49cce3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 30 May 2019 12:28:44 -0700 Subject: [PATCH 026/330] - Upgrade CLI to latest alpha (#25094) Summary: Updates the CLI version to the latest alpha to fix some issues around init and autolinking. Please port this PR back to `0.60-stable` branch as it fixes an issue with `npx react-native init`. cc grabbou hramos ## Changelog [General] [Fix] - Upgrade CLI to latest alpha Pull Request resolved: https://github.com/facebook/react-native/pull/25094 Differential Revision: D15558082 Pulled By: cpojer fbshipit-source-id: 60be64fbed996b6667eddc08346b07475dbb5089 --- package.json | 6 +++--- yarn.lock | 59 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index d9bbd3257e2a31..fb864871321e10 100644 --- a/package.json +++ b/package.json @@ -82,9 +82,9 @@ }, "dependencies": { "@babel/runtime": "^7.0.0", - "@react-native-community/cli": "2.0.0-alpha.20", - "@react-native-community/cli-platform-android": "2.0.0-alpha.20", - "@react-native-community/cli-platform-ios": "2.0.0-alpha.20", + "@react-native-community/cli": "2.0.0-alpha.23", + "@react-native-community/cli-platform-android": "2.0.0-alpha.23", + "@react-native-community/cli-platform-ios": "2.0.0-alpha.23", "abort-controller": "^3.0.0", "art": "^0.10.0", "base64-js": "^1.1.2", diff --git a/yarn.lock b/yarn.lock index 37f37f1218e584..702e94ae62fb01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1090,44 +1090,44 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" -"@react-native-community/cli-platform-android@2.0.0-alpha.20", "@react-native-community/cli-platform-android@^2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-alpha.20.tgz#a3b5aceae38bd3c930f0801b721d44551fe98dc2" - integrity sha512-Z1eWiK4/oZlKvZTPYnORW6uAZ4rgBFMvswldwdy6r9CnjLTZsgw3aGN6r5TUNSCwbZy4p2l5J1pTELl2Ors24g== +"@react-native-community/cli-platform-android@2.0.0-alpha.23", "@react-native-community/cli-platform-android@^2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-alpha.23.tgz#f4941cca17eedef694bf420027b816ecd2e1f1c3" + integrity sha512-V57NWTyi20VQA2EPL1xmiibIQD0bUVe0ecVQxSb903f4M3ml0x4TEqWOToE2wgda/c4Z3pEKJuRCzyZHfuEYPA== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.20" + "@react-native-community/cli-tools" "^2.0.0-alpha.23" logkitty "^0.4.0" - node-fetch "^2.2.0" slash "^2.0.0" xmldoc "^0.4.0" -"@react-native-community/cli-platform-ios@2.0.0-alpha.20", "@react-native-community/cli-platform-ios@^2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-alpha.20.tgz#66eda705b0522b44818806910bbf2b7d47d41b56" - integrity sha512-ZDvx2YU/1cFp5/ADbPUwnlvs5D0RIeEZK4Ddskd2Sx7KIq5jLnQbXW+JDOqie5wQgQQ+eCmebCHnCFBWIGXdMQ== +"@react-native-community/cli-platform-ios@2.0.0-alpha.23", "@react-native-community/cli-platform-ios@^2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-alpha.23.tgz#3ef22cc5d5ce32b85f9f9604056ca3cea652a59a" + integrity sha512-jAffpJNw9zrlI5rwM/BfaTNtKjrx+Rvuei1YqfjLaQKUiXgrbJYbIu9+6Lc+sAn1qFGwL2+CShpywwbvN2ehGQ== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.20" + "@react-native-community/cli-tools" "^2.0.0-alpha.23" chalk "^1.1.1" xcode "^2.0.0" -"@react-native-community/cli-tools@^2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-alpha.20.tgz#7762205a701ffabe6aa0b08d9202dd3d101297d7" - integrity sha512-G2VcBUuG/WmtbgHA4wTPkYqhuRhzE9EH8+4/WnCQmxSi7bfIYAzyVxgpBLCGzFv4liPmtoVuhcsapVeAMOdSlQ== +"@react-native-community/cli-tools@^2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-alpha.23.tgz#001a6ef134e1488bf8ef41dd203fda67f7aed8d6" + integrity sha512-+a+IByj0EXQg6M3Q0aT1hsGSmmqWPPkrx+LeY4Gi2pnmOR+DB9A/dDEDOvwxd/OPBsXqzNmdO+iUcg3HNm/twg== dependencies: chalk "^1.1.1" lodash "^4.17.5" - mime "^1.3.4" + mime "^2.4.1" + node-fetch "^2.5.0" -"@react-native-community/cli@2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-alpha.20.tgz#611fe4ad483755ae10d3f7f915e1ed527f4a9bf8" - integrity sha512-H71a8gYhhI/7F6UzN3vrzQMtl9dmV/iDf55QeRqWEIU1i+SOpXXk5cmcL7hFY4FBUAkjn4o7GAd089RstGIOeA== +"@react-native-community/cli@2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-alpha.23.tgz#321ea633ffdf1160170e4428b5886f4d731ff373" + integrity sha512-NIIRgdqA1IA3+K1l1jcXEtS0qL0aos75GXVwGBOmEkC4TfNoOpVQZl2Ffy+/j+IPGpzl2xecOMMmIvlzQRGDtQ== dependencies: "@hapi/joi" "^15.0.3" - "@react-native-community/cli-platform-android" "^2.0.0-alpha.20" - "@react-native-community/cli-platform-ios" "^2.0.0-alpha.20" - "@react-native-community/cli-tools" "^2.0.0-alpha.20" + "@react-native-community/cli-platform-android" "^2.0.0-alpha.23" + "@react-native-community/cli-platform-ios" "^2.0.0-alpha.23" + "@react-native-community/cli-tools" "^2.0.0-alpha.23" chalk "^1.1.1" command-exists "^1.2.8" commander "^2.19.0" @@ -1150,7 +1150,6 @@ minimist "^1.2.0" mkdirp "^0.5.1" morgan "^1.9.0" - node-fetch "^2.2.0" node-notifier "^5.2.1" open "^6.2.0" ora "^3.4.0" @@ -5184,11 +5183,16 @@ mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19: dependencies: mime-db "~1.36.0" -mime@1.4.1, mime@^1.3.4: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== +mime@^2.4.1: + version "2.4.3" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe" + integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -5369,6 +5373,11 @@ node-fetch@^2.2.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.2.0.tgz#4ee79bde909262f9775f731e3656d0db55ced5b5" integrity sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA== +node-fetch@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" From 00c0fe7d5b1048c987fb3d684a855f78115fdf00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Thu, 30 May 2019 14:19:41 -0700 Subject: [PATCH 027/330] Add method to get a segment path without injecting it in the VM Reviewed By: cpojer Differential Revision: D15495065 fbshipit-source-id: 6537100d8b6dbab68603b7333705d7082c88e3f0 --- .../SegmentFetcher/NativeSegmentFetcher.js | 5 ++ Libraries/Core/setUpSegmentFetcher.js | 47 +++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js index 38319e03456d68..765b8ef0e07ef3 100644 --- a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js +++ b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js @@ -18,6 +18,11 @@ export interface Spec extends TurboModule { options: Object, // flowlint-line unclear-type: off callback: (error: ?Object) => void, // flowlint-line unclear-type: off ) => void; + +getSegment?: ( + segmentId: number, + options: Object, // flowlint-line unclear-type: off + callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off + ) => void; } export default TurboModuleRegistry.getEnforcing('SegmentFetcher'); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js index dd182a69c91bb7..3d811535ce38ee 100644 --- a/Libraries/Core/setUpSegmentFetcher.js +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -9,13 +9,20 @@ */ 'use strict'; +export type FetchSegmentFunction = typeof __fetchSegment; +export type GetSegmentFunction = typeof __getSegment; + /** * Set up SegmentFetcher. * You can use this module directly, or just require InitializeCore. */ -global.__fetchSegment = function( + +function __fetchSegment( segmentId: number, - options: {|+otaBuildNumber: ?string|}, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, callback: (?Error) => void, ) { const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') @@ -33,4 +40,38 @@ global.__fetchSegment = function( callback(null); }, ); -}; +} + +global.__fetchSegment = __fetchSegment; + +function __getSegment( + segmentId: number, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, + callback: (?Error, ?string) => void, +) { + const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') + .default; + + if (!SegmentFetcher.getSegment) { + throw new Error('SegmentFetcher.getSegment must be defined'); + } + + SegmentFetcher.getSegment( + segmentId, + options, + (errorObject: ?{message: string, code: string}, path: ?string) => { + if (errorObject) { + const error = new Error(errorObject.message); + (error: any).code = errorObject.code; // flowlint-line unclear-type: off + callback(error); + } + + callback(null, path); + }, + ); +} + +global.__getSegment = __getSegment; From 5705ea1752b8f2fd3941b457a30a95ac9069aab3 Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Thu, 30 May 2019 14:23:39 -0700 Subject: [PATCH 028/330] Add spec for WebSocketModule (#24893) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for WebSocketModule Pull Request resolved: https://github.com/facebook/react-native/pull/24893 Reviewed By: RSNara Differential Revision: D15551329 Pulled By: fkgozali fbshipit-source-id: 59a921c50cc162528b2181fdd4cb1e41e3f1f6eb --- Libraries/WebSocket/NativeWebSocketModule.js | 33 ++++++++++++++++++ Libraries/WebSocket/WebSocket.js | 15 ++++----- Libraries/WebSocket/WebSocketInterceptor.js | 35 +++++++++++--------- 3 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 Libraries/WebSocket/NativeWebSocketModule.js diff --git a/Libraries/WebSocket/NativeWebSocketModule.js b/Libraries/WebSocket/NativeWebSocketModule.js new file mode 100644 index 00000000000000..0b595b51b02861 --- /dev/null +++ b/Libraries/WebSocket/NativeWebSocketModule.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +connect: ( + url: string, + protocols: ?Array, + options: ?{headers?: {origin?: string}}, + socketID: number, + ) => void; + +send: (message: string, socketID: number) => void; + +sendBinary: (base64String: string, socketID: number) => void; + +ping: (socketID: number) => void; + +close: (code: number, reason: string, socketID: number) => void; + + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.getEnforcing('WebSocketModule'); diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 472fd833e63096..47d56c7eecd7d7 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -14,7 +14,6 @@ const Blob = require('../Blob/Blob'); const EventTarget = require('event-target-shim'); const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); const BlobManager = require('../Blob/BlobManager'); -const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); const WebSocketEvent = require('./WebSocketEvent'); @@ -22,7 +21,7 @@ const base64 = require('base64-js'); const binaryToBase64 = require('../Utilities/binaryToBase64'); const invariant = require('invariant'); -const {WebSocketModule} = NativeModules; +import NativeWebSocketModule from './NativeWebSocketModule'; import type EventSubscription from '../vendor/emitter/EventSubscription'; @@ -128,10 +127,10 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { protocols = null; } - this._eventEmitter = new NativeEventEmitter(WebSocketModule); + this._eventEmitter = new NativeEventEmitter(NativeWebSocketModule); this._socketId = nextWebSocketId++; this._registerEvents(); - WebSocketModule.connect(url, protocols, {headers}, this._socketId); + NativeWebSocketModule.connect(url, protocols, {headers}, this._socketId); } get binaryType(): ?BinaryType { @@ -180,12 +179,12 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { } if (typeof data === 'string') { - WebSocketModule.send(data, this._socketId); + NativeWebSocketModule.send(data, this._socketId); return; } if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) { - WebSocketModule.sendBinary(binaryToBase64(data), this._socketId); + NativeWebSocketModule.sendBinary(binaryToBase64(data), this._socketId); return; } @@ -197,14 +196,14 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { throw new Error('INVALID_STATE_ERR'); } - WebSocketModule.ping(this._socketId); + NativeWebSocketModule.ping(this._socketId); } _close(code?: number, reason?: string): void { // See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent const statusCode = typeof code === 'number' ? code : CLOSE_NORMAL; const closeReason = typeof reason === 'string' ? reason : ''; - WebSocketModule.close(statusCode, closeReason, this._socketId); + NativeWebSocketModule.close(statusCode, closeReason, this._socketId); if (BlobManager.isAvailable && this._binaryType === 'blob') { BlobManager.removeWebSocketHandler(this._socketId); diff --git a/Libraries/WebSocket/WebSocketInterceptor.js b/Libraries/WebSocket/WebSocketInterceptor.js index 58cd3da3a3b7d7..6c371c1028c485 100644 --- a/Libraries/WebSocket/WebSocketInterceptor.js +++ b/Libraries/WebSocket/WebSocketInterceptor.js @@ -9,16 +9,16 @@ 'use strict'; -const RCTWebSocketModule = require('../BatchedBridge/NativeModules') - .WebSocketModule; const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); +import NativeWebSocketModule from './NativeWebSocketModule'; + const base64 = require('base64-js'); -const originalRCTWebSocketConnect = RCTWebSocketModule.connect; -const originalRCTWebSocketSend = RCTWebSocketModule.send; -const originalRCTWebSocketSendBinary = RCTWebSocketModule.sendBinary; -const originalRCTWebSocketClose = RCTWebSocketModule.close; +const originalRCTWebSocketConnect = NativeWebSocketModule.connect; +const originalRCTWebSocketSend = NativeWebSocketModule.send; +const originalRCTWebSocketSendBinary = NativeWebSocketModule.sendBinary; +const originalRCTWebSocketClose = NativeWebSocketModule.close; let eventEmitter: NativeEventEmitter; let subscriptions: Array; @@ -135,13 +135,18 @@ const WebSocketInterceptor = { if (isInterceptorEnabled) { return; } - eventEmitter = new NativeEventEmitter(RCTWebSocketModule); + eventEmitter = new NativeEventEmitter(NativeWebSocketModule); WebSocketInterceptor._registerEvents(); // Override `connect` method for all RCTWebSocketModule requests // to intercept the request url, protocols, options and socketId, // then pass them through the `connectCallback`. - RCTWebSocketModule.connect = function(url, protocols, options, socketId) { + NativeWebSocketModule.connect = function( + url, + protocols, + options, + socketId, + ) { if (connectCallback) { connectCallback(url, protocols, options, socketId); } @@ -150,7 +155,7 @@ const WebSocketInterceptor = { // Override `send` method for all RCTWebSocketModule requests to intercept // the data sent, then pass them through the `sendCallback`. - RCTWebSocketModule.send = function(data, socketId) { + NativeWebSocketModule.send = function(data, socketId) { if (sendCallback) { sendCallback(data, socketId); } @@ -159,7 +164,7 @@ const WebSocketInterceptor = { // Override `sendBinary` method for all RCTWebSocketModule requests to // intercept the data sent, then pass them through the `sendCallback`. - RCTWebSocketModule.sendBinary = function(data, socketId) { + NativeWebSocketModule.sendBinary = function(data, socketId) { if (sendCallback) { sendCallback(WebSocketInterceptor._arrayBufferToString(data), socketId); } @@ -168,7 +173,7 @@ const WebSocketInterceptor = { // Override `close` method for all RCTWebSocketModule requests to intercept // the close information, then pass them through the `closeCallback`. - RCTWebSocketModule.close = function() { + NativeWebSocketModule.close = function() { if (closeCallback) { if (arguments.length === 3) { closeCallback(arguments[0], arguments[1], arguments[2]); @@ -203,10 +208,10 @@ const WebSocketInterceptor = { return; } isInterceptorEnabled = false; - RCTWebSocketModule.send = originalRCTWebSocketSend; - RCTWebSocketModule.sendBinary = originalRCTWebSocketSendBinary; - RCTWebSocketModule.close = originalRCTWebSocketClose; - RCTWebSocketModule.connect = originalRCTWebSocketConnect; + NativeWebSocketModule.send = originalRCTWebSocketSend; + NativeWebSocketModule.sendBinary = originalRCTWebSocketSendBinary; + NativeWebSocketModule.close = originalRCTWebSocketClose; + NativeWebSocketModule.connect = originalRCTWebSocketConnect; connectCallback = null; closeCallback = null; From 7fd08e146184432731ec5d5ba210e352690dc569 Mon Sep 17 00:00:00 2001 From: Tom Sanderson Date: Thu, 30 May 2019 14:23:39 -0700 Subject: [PATCH 029/330] add spec for PlatformConstants (#24928) Summary: part of #24875. ## Changelog [General] [Added] - add TM spec for PlatformConstants Pull Request resolved: https://github.com/facebook/react-native/pull/24928 Reviewed By: RSNara Differential Revision: D15551340 Pulled By: fkgozali fbshipit-source-id: 9de15ff4cfe717f963332868bd873d5147a37506 --- .../Animated/src/__tests__/Animated-test.js | 5 +++ .../src/__tests__/AnimatedNative-test.js | 5 +++ Libraries/Core/ReactNativeVersionCheck.js | 11 +++--- .../__tests__/ReactNativeVersionCheck-test.js | 11 ++++-- .../Network/__tests__/XMLHttpRequest-test.js | 5 +++ .../NativePlatformConstantsAndroid.js | 36 +++++++++++++++++++ .../Utilities/NativePlatformConstantsIOS.js | 32 +++++++++++++++++ Libraries/Utilities/Platform.android.js | 14 ++++---- Libraries/Utilities/Platform.ios.js | 17 +++++---- .../js/examples/Touchable/TouchableExample.js | 5 +-- jest/setup.js | 5 +++ 11 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 Libraries/Utilities/NativePlatformConstantsAndroid.js create mode 100644 Libraries/Utilities/NativePlatformConstantsIOS.js diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/src/__tests__/Animated-test.js index fbfdc5dd73f3a1..4e74cb6200e3c0 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/src/__tests__/Animated-test.js @@ -12,6 +12,11 @@ jest.mock('../../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, + PlatformConstants: { + getConstants() { + return {}; + }, + }, })); let Animated = require('../Animated'); diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/src/__tests__/AnimatedNative-test.js index 38e201928c2e5e..09b087ce5d5be0 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/src/__tests__/AnimatedNative-test.js @@ -24,6 +24,11 @@ jest .setMock('react', {Component: class {}}) .mock('../../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, + PlatformConstants: { + getConstants() { + return {}; + }, + }, })) .mock('../NativeAnimatedModule') .mock('../../../EventEmitter/NativeEventEmitter') diff --git a/Libraries/Core/ReactNativeVersionCheck.js b/Libraries/Core/ReactNativeVersionCheck.js index 30264918c79221..a2eb4d050fc90c 100644 --- a/Libraries/Core/ReactNativeVersionCheck.js +++ b/Libraries/Core/ReactNativeVersionCheck.js @@ -9,7 +9,7 @@ */ 'use strict'; -const {PlatformConstants} = require('../BatchedBridge/NativeModules'); +import Platform from '../Utilities/Platform'; const ReactNativeVersion = require('./ReactNativeVersion'); /** @@ -22,11 +22,7 @@ const ReactNativeVersion = require('./ReactNativeVersion'); * and rely on its existence as a separate module. */ exports.checkVersions = function checkVersions(): void { - if (!PlatformConstants) { - return; - } - - const nativeVersion = PlatformConstants.reactNativeVersion; + const nativeVersion = Platform.constants.reactNativeVersion; if ( ReactNativeVersion.version.major !== nativeVersion.major || ReactNativeVersion.version.minor !== nativeVersion.minor @@ -46,6 +42,7 @@ exports.checkVersions = function checkVersions(): void { function _formatVersion(version): string { return ( `${version.major}.${version.minor}.${version.patch}` + - (version.prerelease !== null ? `-${version.prerelease}` : '') + // eslint-disable-next-line eqeqeq + (version.prerelease != undefined ? `-${version.prerelease}` : '') ); } diff --git a/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js b/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js index 471a6f00308c3a..70c8abd88e2f24 100644 --- a/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js +++ b/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js @@ -127,9 +127,14 @@ function _mockNativeVersion( patch = 0, prerelease = null, ) { - jest.doMock('../../BatchedBridge/NativeModules', () => ({ - PlatformConstants: { + jest.doMock('../../Utilities/NativePlatformConstantsAndroid', () => ({ + getConstants: () => ({ reactNativeVersion: {major, minor, patch, prerelease}, - }, + }), + })); + jest.doMock('../../Utilities/NativePlatformConstantsIOS', () => ({ + getConstants: () => ({ + reactNativeVersion: {major, minor, patch, prerelease}, + }), })); } diff --git a/Libraries/Network/__tests__/XMLHttpRequest-test.js b/Libraries/Network/__tests__/XMLHttpRequest-test.js index e69e91b55d6b1c..0520348f380646 100644 --- a/Libraries/Network/__tests__/XMLHttpRequest-test.js +++ b/Libraries/Network/__tests__/XMLHttpRequest-test.js @@ -34,6 +34,11 @@ jest }, abortRequest: function() {}, }, + PlatformConstants: { + getConstants() { + return {}; + }, + }, }); const XMLHttpRequest = require('../XMLHttpRequest'); diff --git a/Libraries/Utilities/NativePlatformConstantsAndroid.js b/Libraries/Utilities/NativePlatformConstantsAndroid.js new file mode 100644 index 00000000000000..ba952618b95600 --- /dev/null +++ b/Libraries/Utilities/NativePlatformConstantsAndroid.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + Version: number, + Release: string, + Serial: string, + Fingerprint: string, + Model: string, + ServerHost: string, + uiMode: string, + |}; + +getAndroidID: () => string; +} + +export default TurboModuleRegistry.getEnforcing('PlatformConstants'); diff --git a/Libraries/Utilities/NativePlatformConstantsIOS.js b/Libraries/Utilities/NativePlatformConstantsIOS.js new file mode 100644 index 00000000000000..b350a6ee477b67 --- /dev/null +++ b/Libraries/Utilities/NativePlatformConstantsIOS.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + forceTouchAvailable: boolean, + osVersion: string, + systemName: string, + interfaceIdiom: string, + |}; +} + +export default TurboModuleRegistry.getEnforcing('PlatformConstants'); diff --git a/Libraries/Utilities/Platform.android.js b/Libraries/Utilities/Platform.android.js index 40b7a83034efbc..d7e672b33b863b 100644 --- a/Libraries/Utilities/Platform.android.js +++ b/Libraries/Utilities/Platform.android.js @@ -10,7 +10,7 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativePlatformConstantsAndroid from './NativePlatformConstantsAndroid'; export type PlatformSelectSpec = { android?: A, @@ -20,19 +20,19 @@ export type PlatformSelectSpec = { const Platform = { OS: 'android', get Version() { - const constants = NativeModules.PlatformConstants; - return constants && constants.Version; + return NativePlatformConstantsAndroid.getConstants().Version; + }, + get constants() { + return NativePlatformConstantsAndroid.getConstants(); }, get isTesting(): boolean { if (__DEV__) { - const constants = NativeModules.PlatformConstants; - return constants && constants.isTesting; + return NativePlatformConstantsAndroid.getConstants().isTesting; } return false; }, get isTV(): boolean { - const constants = NativeModules.PlatformConstants; - return constants && constants.uiMode === 'tv'; + return NativePlatformConstantsAndroid.getConstants().uiMode === 'tv'; }, select: (spec: PlatformSelectSpec): A | D => 'android' in spec ? spec.android : spec.default, diff --git a/Libraries/Utilities/Platform.ios.js b/Libraries/Utilities/Platform.ios.js index 2ac52e3005a061..f558755c6f0b02 100644 --- a/Libraries/Utilities/Platform.ios.js +++ b/Libraries/Utilities/Platform.ios.js @@ -10,7 +10,7 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativePlatformConstantsIOS from './NativePlatformConstantsIOS'; export type PlatformSelectSpec = { default?: D, @@ -20,12 +20,13 @@ export type PlatformSelectSpec = { const Platform = { OS: 'ios', get Version() { - const constants = NativeModules.PlatformConstants; - return constants && constants.osVersion; + return NativePlatformConstantsIOS.getConstants().osVersion; + }, + get constants() { + return NativePlatformConstantsIOS.getConstants(); }, get isPad() { - const constants = NativeModules.PlatformConstants; - return constants ? constants.interfaceIdiom === 'pad' : false; + return NativePlatformConstantsIOS.getConstants().interfaceIdiom === 'pad'; }, /** * Deprecated, use `isTV` instead. @@ -34,13 +35,11 @@ const Platform = { return Platform.isTV; }, get isTV() { - const constants = NativeModules.PlatformConstants; - return constants ? constants.interfaceIdiom === 'tv' : false; + return NativePlatformConstantsIOS.getConstants().interfaceIdiom === 'tv'; }, get isTesting(): boolean { if (__DEV__) { - const constants = NativeModules.PlatformConstants; - return constants && constants.isTesting; + return NativePlatformConstantsIOS.getConstants().isTesting; } return false; }, diff --git a/RNTester/js/examples/Touchable/TouchableExample.js b/RNTester/js/examples/Touchable/TouchableExample.js index 7e4e348cb3a2b8..f77b7db9a548d0 100644 --- a/RNTester/js/examples/Touchable/TouchableExample.js +++ b/RNTester/js/examples/Touchable/TouchableExample.js @@ -18,7 +18,6 @@ const { Text, TouchableHighlight, TouchableOpacity, - NativeModules, Platform, TouchableNativeFeedback, TouchableWithoutFeedback, @@ -26,9 +25,7 @@ const { } = require('react-native'); const forceTouchAvailable = - (NativeModules.PlatformConstants && - NativeModules.PlatformConstants.forceTouchAvailable) || - false; + (Platform.OS === 'ios' && Platform.constants.forceTouchAvailable) || false; class TouchableHighlightBox extends React.Component<{}, $FlowFixMeState> { state = { diff --git a/jest/setup.js b/jest/setup.js index e03244ed5d982b..38cef7befbf12f 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -236,6 +236,11 @@ const mockNativeModules = { addListener: jest.fn(), removeListeners: jest.fn(), }, + PlatformConstants: { + getConstants() { + return {}; + }, + }, PushNotificationManager: { presentLocalNotification: jest.fn(), scheduleLocalNotification: jest.fn(), From 171cc0edb703e8e502d423b3eed9eb914c74e021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Thu, 30 May 2019 15:07:45 -0700 Subject: [PATCH 030/330] Migrate to Circle CI 2.1 (#25036) Summary: Migrate the Circle CI configuration to the 2.1 schema and take advantage of new config reuse features. I've enabled pipelines in the facebook/react-native Circle CI project, a requirement for Circle CI 2.1 features. ### Overview * Use executors to provide a common set of execution environments. * Use commands to provide reusable steps (running yarn with cache, installing Android dependencies, ...) * Use parametrized commands/jobs to reuse job definitions for `test_js` and `test_js_lts` where the only difference is the version of node provided by the environment. * Reduce total execution time by [storing the git repo in a cache as opposed to using workspaces](https://circleci.com/blog/persisting-data-in-workflows-when-to-use-caching-artifacts-and-workspaces/) * Fix various flaky end-to-end test failures related to CocoaPods and the CLI. * Move `analyze` job to `analysis` workflow and rename to `analyze_pr` * Rename `test_javascript` as `test_js`. * Split up end-to-end test job into `test_ios_e2e` and `test_js_e2e`. ## Changelog [Internal] [Changed] - Migrate to Circle CI 2.1 and fix e2e tests Pull Request resolved: https://github.com/facebook/react-native/pull/25036 Differential Revision: D15565515 Pulled By: hramos fbshipit-source-id: cfba2154a9fdc96400cbf778bd5d13e9411ee3f8 --- .circleci/config.yml | 698 ++++++++++++++++++------------------ scripts/run-ci-e2e-tests.js | 49 ++- 2 files changed, 374 insertions(+), 373 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d38432f3e37c65..64630eaf6c5753 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,143 +1,4 @@ -# ------------------------- -# ALIASES -# ------------------------- -aliases: - # ------------------------- - # ALIASES: Caches - # ------------------------- - - &restore-yarn-cache - keys: - - v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} - - v1-yarn-cache-{{ arch }} - - - &save-yarn-cache - paths: - - ~/.cache/yarn - key: v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} - - - &restore-brew-cache - keys: - - v1-brew - - - &save-brew-cache - paths: - - /usr/local/Homebrew - - ~/Library/Caches/Homebrew - key: v1-brew - - # Android - - &restore-buck-downloads-cache - keys: - - v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} - - v3-buck-v2019.01.10.01- - - &save-buck-downloads-cache - paths: - - ~/buck - - ~/okbuck - key: v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }} - - - &restore-gradle-downloads-cache - keys: - - v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} - - v1-gradle- - - - &save-gradle-downloads-cache - paths: - - ~/.gradle - - ReactAndroid/build/downloads - - ReactAndroid/build/third-party-ndk - key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} - - # ------------------------- - # ALIASES: Shared Commands - # ------------------------- - - &yarn - name: Run Yarn - command: | - # Skip yarn install on metro bump commits as the package is not yet - # available on npm - if [[ $(echo "$GIT_COMMIT_DESC" | grep -c "Bump metro@") -eq 0 ]]; then - yarn install --non-interactive --cache-folder ~/.cache/yarn - fi - - - &setup-artifacts - name: Initial Setup - command: | - mkdir -p ~/react-native/reports/buck/ - mkdir -p ~/react-native/reports/build/ - mkdir -p ~/react-native/reports/junit/ - mkdir -p ~/react-native/reports/outputs/ - - # Android - - &download-dependencies-buck - name: Download Dependencies Using Buck - command: ./scripts/circleci/buck_fetch.sh - - - &download-dependencies-gradle - name: Download Dependencies Using Gradle - command: ./scripts/circleci/gradle_download_deps.sh - - # JavaScript - - &run-js-tests - name: JavaScript Test Suite - command: yarn test-ci - - # ------------------------- - # ALIASES: Disabled Tests - # ------------------------- - - &run-podspec-tests - name: Test CocoaPods - command: ./scripts/process-podspecs.sh - - &run-e2e-tests - name: End-to-End Test Suite - command: ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3; - - &run-android-e2e-tests - name: Android End-to-End Test Suite - command: node ./scripts/run-ci-e2e-tests.js --android --retries 3; - - - # ------------------------- - # ALIASES: Branch Filters - # ------------------------- - - &filter-only-master - branches: - only: master - - - &filter-only-master-stable - branches: - only: - - /.*-stable/ - - master - - - &filter-only-stable - branches: - only: - - /.*-stable/ - - - &filter-ignore-gh-pages - branches: - ignore: gh-pages - - - &filter-only-version-tags - # Both of the following conditions must be included! - # Ignore any commit on any branch by default. - branches: - ignore: /.*/ - # Only act on version tags. - tags: - only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ - - - &filter-only-forked-pull-requests - branches: - only: /^pull\/.*$/ - - # ------------------------- - # ALIASES: Workflows - # ------------------------- - - &run-after-checkout - filters: *filter-ignore-gh-pages - requires: - - checkout_code +version: 2.1 # ------------------------- # DEFAULTS @@ -147,50 +8,175 @@ defaults: &defaults environment: - GIT_COMMIT_DESC: git log --format=oneline -n 1 $CIRCLE_SHA1 -# JavaScript -js_defaults: &js_defaults - <<: *defaults - docker: - - image: node:8 - -# Android -android_defaults: &android_defaults - <<: *defaults - docker: - - image: reactnativecommunity/react-native-android:2019-5-7 - resource_class: "large" - environment: - - TERM: "dumb" - - ADB_INSTALL_TIMEOUT: 10 - - _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" - - GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"' - - BUILD_THREADS: 2 - -# iOS -macos_defaults: &macos_defaults - <<: *defaults - macos: - xcode: "10.2.0" +# ------------------------- +# EXECUTORS +# ------------------------- +executors: + node8: + <<: *defaults + docker: + - image: circleci/node:8 + nodelts: + <<: *defaults + docker: + - image: circleci/node:lts + reactnativeandroid: + <<: *defaults + docker: + - image: reactnativecommunity/react-native-android:2019-5-29 + resource_class: "large" + environment: + - TERM: "dumb" + - ADB_INSTALL_TIMEOUT: 10 + - _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" + - GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"' + - BUILD_THREADS: 2 + reactnativeios: + <<: *defaults + macos: + xcode: "10.2.0" + +# ------------------------- +# COMMANDS +# ------------------------- +commands: + restore_cache_checkout: + parameters: + checkout_type: + type: string + default: node + steps: + - restore_cache: + key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}-<< parameters.checkout_type >> + + setup_artifacts: + steps: + - run: + name: Initial Setup + command: mkdir -p ~/reports/{buck,build,junit,outputs} + + run_yarn: + steps: + - restore_cache: + keys: + - v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} + - v2-yarn-cache-{{ arch }} + - run: + name: Run Yarn + command: | + # Skip yarn install on metro bump commits as the package is not yet + # available on npm + if [[ $(echo "$GIT_COMMIT_DESC" | grep -c "Bump metro@") -eq 0 ]]; then + yarn install --non-interactive --cache-folder ~/.cache/yarn + fi + - save_cache: + paths: + - ~/.cache/yarn + key: v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} + + install_buck_tooling: + steps: + - restore_cache: + keys: + - v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} + - v3-buck-v2019.01.10.01- + - run: + name: Install BUCK + command: | + buck --version + # Install related tooling + if [[ ! -e ~/okbuck ]]; then + git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1 + fi + - save_cache: + paths: + - ~/buck + - ~/okbuck + key: v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }} + + brew_install: + parameters: + package: + description: Homebrew package to install + type: string + steps: + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install << parameters.package >> >/dev/null + + with_brew_cache_span: + parameters: + steps: + type: steps + steps: + - restore_cache: + keys: + - v1-brew + - steps: << parameters.steps >> + - save_cache: + paths: + - /usr/local/Homebrew + - ~/Library/Caches/Homebrew + key: v1-brew + + download_gradle_dependencies: + steps: + - restore_cache: + keys: + - v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + - v1-gradle- + - run: + name: Download Dependencies Using Gradle + command: ./scripts/circleci/gradle_download_deps.sh + - save_cache: + paths: + - ~/.gradle + - ReactAndroid/build/downloads + - ReactAndroid/build/third-party-ndk + key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + + download_buck_dependencies: + steps: + - run: + name: Download Dependencies Using Buck + command: ./scripts/circleci/buck_fetch.sh + + # ------------------------- + # COMMANDS: Disabled Tests + # ------------------------- + run_podspec_tests: + steps: + - run: + name: Test CocoaPods + command: ./scripts/process-podspecs.sh + run_e2e_tests: + steps: + - run: + name: Full End-to-End Test Suite + command: node ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3; + run_android_e2e_tests: + steps: + - run: + name: Android End-to-End Test Suite + command: node ./scripts/run-ci-e2e-tests.js --android --retries 3; # ------------------------- # JOBS # ------------------------- -version: 2 jobs: - # Set up a Node environment for downstream jobs - checkout_code: - <<: *js_defaults + setup: + parameters: + executor: + type: executor + default: node8 + checkout_type: + type: string + default: node + executor: << parameters.executor >> steps: - checkout - - run: *setup-artifacts - - - restore-cache: *restore-yarn-cache - - run: *yarn - - save-cache: *save-yarn-cache - - - persist_to_workspace: - root: . - paths: . + - save_cache: + key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}-<< parameters.checkout_type >> + paths: + - ~/react-native # ------------------------- # JOBS: Analyze PR @@ -199,9 +185,7 @@ jobs: # Issues will be posted to the PR itself via GitHub bots. # This workflow should only fail if the bots fail to run. analyze_pr: - <<: *defaults - docker: - - image: node:lts + executor: nodelts # The public github tokens are publicly visible by design environment: - PUBLIC_PULLBOT_GITHUB_TOKEN_A: "a6edf8e8d40ce4e8b11a" @@ -210,19 +194,15 @@ jobs: - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: "b1a98e0bbd56ff1ccba1" steps: - - checkout - - run: *setup-artifacts + - restore_cache_checkout: + checkout_type: node + - run_yarn - - restore-cache: *restore-yarn-cache - - run: *yarn - run: name: Install dependencies command: | - apt update - apt install -y shellcheck jq - cd bots - yarn install --non-interactive --cache-folder ~/.cache/yarn - - save-cache: *save-yarn-cache + sudo apt update && sudo apt install -y shellcheck jq + cd bots && yarn install --non-interactive --cache-folder ~/.cache/yarn - run: name: Run linters against modified files (analysis-bot) @@ -240,15 +220,17 @@ jobs: # ------------------------- # JOBS: Analyze Code # ------------------------- - analyze: - <<: *js_defaults + analyze_code: + executor: node8 steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn - run: name: Lint code - command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/react-native/reports/junit/eslint/results.xml + command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/reports/junit/eslint/results.xml when: always - run: @@ -274,56 +256,43 @@ jobs: when: always - store_test_results: - path: ~/react-native/reports/junit - - store_artifacts: - path: ~/react-native/yarn.lock + path: ~/reports/junit # ------------------------- # JOBS: Test JavaScript # ------------------------- - # Runs JavaScript tests on Node 8 - test_javascript: - <<: *js_defaults + # Runs JavaScript tests + test_js: + parameters: + executor: + type: executor + default: node8 + executor: << parameters.executor >> steps: - - attach_workspace: - at: ~/react-native - - - run: - name: JavaScript Test Suite - command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2 - - - store_test_results: - path: ~/react-native/reports/junit - - # Run JavaScript tests on Node LTS - test_node_lts: - <<: *defaults - docker: - - image: node:lts - steps: - - checkout - - run: *setup-artifacts - - - run: *yarn + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn - run: name: JavaScript Test Suite command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2 - store_test_results: - path: ~/react-native/reports/junit - + path: ~/reports/junit # ------------------------- # JOBS: Test iOS # ------------------------- # Runs unit tests on iOS devices test_ios: - <<: *macos_defaults + executor: reactnativeios environment: - REPORTS_DIR: "./reports" steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: ios + - setup_artifacts + - run_yarn - run: name: Print Xcode environment @@ -337,13 +306,11 @@ jobs: name: Boot iOS Simulator command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true - - restore-cache: *restore-brew-cache - - run: - name: Install Watchman - command: | - HOMEBREW_NO_AUTO_UPDATE=1 brew install watchman >/dev/null - touch .watchmanconfig - - save-cache: *save-brew-cache + - with_brew_cache_span: + steps: + - brew_install: + package: watchman + - run: touch .watchmanconfig - run: name: Start Metro packager @@ -433,14 +400,16 @@ jobs: lsof -i tcp:5555 | awk 'NR!=1 {print $2}' | xargs kill - store_test_results: - path: ~/react-native/reports/junit + path: ~/reports/junit - # Runs end-to-end tests - test_end_to_end: - <<: *macos_defaults + # Runs iOS end-to-end tests + test_ios_e2e: + executor: reactnativeios steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: ios + - setup_artifacts + - run_yarn - run: name: Boot iPhone Simulator @@ -453,41 +422,20 @@ jobs: source $BASH_ENV # Brew - - restore-cache: *restore-brew-cache - - run: - name: Configure Detox Environment - command: | - HOMEBREW_NO_AUTO_UPDATE=1 brew install node@8 >/dev/null - HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null - HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null - touch .watchmanconfig - node -v - - save-cache: *save-brew-cache + - with_brew_cache_span: + steps: + - brew_install: + package: node@8 + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null + - brew_install: + package: applesimutils - # Yarn install - - restore-cache: *restore-yarn-cache - - run: *yarn - - save-cache: *save-yarn-cache + # Configure Watchman + - run: touch .watchmanconfig - # Xcode build - - run: - name: Build app for Detox iOS End-to-End Tests - command: yarn run build-ios-e2e - - # Test - run: name: Run Detox iOS End-to-End Tests - command: yarn run test-ios-e2e - when: always - - - run: - name: Run JavaScript End-to-End Tests - command: | - # free up port 8081 for the packager before running tests - set +eo pipefail - lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill - set -eo pipefail - node ./scripts/run-ci-e2e-tests.js --js --retries 3 + command: yarn run build-ios-e2e && yarn run test-ios-e2e when: always - run: @@ -500,15 +448,32 @@ jobs: node ./scripts/run-ci-e2e-tests.js --ios --retries 3; when: always + test_js_e2e: + executor: node8 + steps: + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn + + - run: + name: Run JavaScript End-to-End Tests + command: node ./scripts/run-ci-e2e-tests.js --js --retries 3 + + - store_test_results: + path: ~/reports/junit + # ------------------------- # JOBS: Test Android # ------------------------- # Run Android tests test_android: - <<: *android_defaults + executor: reactnativeandroid steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: android + - setup_artifacts + - run_yarn # Validate Android SDK installation and packages - run: @@ -527,31 +492,15 @@ jobs: # Keep configuring Android dependencies while AVD boots up # Install Buck - - restore-cache: *restore-buck-downloads-cache - - run: - name: Install BUCK - command: | - buck --version - # Install related tooling - if [[ ! -e ~/okbuck ]]; then - git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1 - fi - mkdir -p ~/react-native/tooling/junit - cp -R ~/okbuck/tooling/junit/* ~/react-native/tooling/junit/. - - save-cache: *save-buck-downloads-cache + - install_buck_tooling # Validate Android test environment (including Buck) - run: name: Validate Android Test Environment command: ./scripts/validate-android-test-env.sh - # Download dependencies using Buck - - run: *download-dependencies-buck - - # Download dependencies using Gradle - - restore-cache: *restore-gradle-downloads-cache - - run: *download-dependencies-gradle - - save-cache: *save-gradle-downloads-cache + - download_buck_dependencies + - download_gradle_dependencies # Build and compile - run: @@ -577,7 +526,7 @@ jobs: # Test Suite - run: name: Run Unit Tests - command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ~/react-native/reports/buck/all-results-raw.xml + command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ~/reports/buck/all-results-raw.xml - run: name: Run Instrumentation Tests @@ -595,19 +544,19 @@ jobs: - run: name: Collect Test Results command: | - find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/react-native/reports/build/ \; - find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/react-native/reports/outputs/ \; - find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/react-native/reports/buck/ \; - ./tooling/junit/buck_to_junit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/all-results-junit.xml + find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/reports/build/ \; + find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/reports/outputs/ \; + find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/reports/buck/ \; + ~/okbuck/tooling/junit/buck_to_junit.sh ~/reports/buck/all-results-raw.xml ~/reports/junit/all-results-junit.xml when: always - store_test_results: - path: ~/react-native/reports/junit + path: ~/reports/junit # ------------------------- - # JOBS: Test Docker Build + # JOBS: Test Docker # ------------------------- - test_docker_build: + test_docker: machine: true steps: - checkout @@ -626,16 +575,17 @@ jobs: # ------------------------- # Collect JavaScript test coverage js_coverage: - <<: *js_defaults + executor: node8 environment: - CI_BRANCH: $CIRCLE_BRANCH - CI_PULL_REQUEST: $CIRCLE_PULL_REQUEST - CI_BUILD_NUMBER: $CIRCLE_BUILD_NUM - CI_BUILD_URL: $CIRCLE_BUILD_URL steps: - - checkout - - restore-cache: *restore-yarn-cache - - run: *yarn + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn - run: name: Test coverage command: | @@ -651,73 +601,113 @@ jobs: # Publishes new version onto npm # Only works on stable branches when a properly tagged commit is pushed publish_npm_package: - <<: *android_defaults + executor: reactnativeandroid steps: - - checkout - - - restore-cache: *restore-yarn-cache - - run: *yarn - - # Fetch dependencies using Buck - - restore-cache: *restore-buck-downloads-cache - - run: *download-dependencies-buck - - # Fetch dependencies using Gradle - - restore-cache: *restore-gradle-downloads-cache - - run: *download-dependencies-gradle - - - restore-cache: *restore-yarn-cache - - run: *yarn - - - run: - name: Authenticate with npm - command: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc - - - run: - name: Authenticate git user - command: | - git config --global user.email "react-native-bot@users.noreply.github.com" - git config --global user.name "npm Deployment Script" - echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc - - # Build and publish release. Requires an Android environment. - - run: - name: Publish React Native Package - command: node ./scripts/publish-npm.js + - restore_cache_checkout: + checkout_type: android + - run_yarn + - install_buck_tooling + - download_buck_dependencies + - download_gradle_dependencies + - run: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc + - run: | + git config --global user.email "react-native-bot@users.noreply.github.com" + git config --global user.name "npm Deployment Script" + echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc + - run: node ./scripts/publish-npm.js # ------------------------- # WORK FLOWS # ------------------------- workflows: - version: 2 - tests: jobs: - - test_node_lts: - filters: *filter-ignore-gh-pages - - - checkout_code: - filters: *filter-ignore-gh-pages - - - analyze: *run-after-checkout - - test_javascript: *run-after-checkout - - test_android: *run-after-checkout - - test_ios: *run-after-checkout - - test_end_to_end: *run-after-checkout - - test_docker_build: - filters: *filter-ignore-gh-pages - + - setup: + name: setup_js + filters: + branches: + ignore: gh-pages + - setup: + name: setup_ios + checkout_type: ios + executor: reactnativeios + filters: + branches: + ignore: gh-pages + - setup: + name: setup_android + checkout_type: android + executor: reactnativeandroid + filters: + branches: + ignore: gh-pages + - test_js: + requires: + - setup_js + - test_js_e2e: + requires: + - setup_js + - test_js + - test_android: + requires: + - setup_android + - test_ios: + requires: + - setup_ios + - test_ios_e2e: + requires: + - setup_ios + - test_js + - test_js: + name: test_js_lts + executor: nodelts + requires: + - setup_js + - test_docker: + filters: + branches: + ignore: gh-pages releases: jobs: + - setup: + name: setup_android + checkout_type: android + executor: reactnativeandroid + filters: + # Both of the following conditions must be included! + # Ignore any commit on any branch by default. + branches: + ignore: /.*/ + # Only act on version tags. + tags: + only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ - publish_npm_package: - filters: *filter-only-version-tags + requires: + - setup_android analysis: jobs: + - setup + # Run lints on every commit other than those to the gh-pages branch + - analyze_code: + requires: + - setup + filters: + branches: + ignore: gh-pages + # Run code checks on PRs from forks - analyze_pr: - filters: *filter-only-forked-pull-requests + requires: + - setup + filters: + branches: + only: /^pull\/.*$/ # Gather coverage on master - js_coverage: - filters: *filter-only-master + requires: + - setup + filters: + branches: + only: master diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index 95312e7998d57a..b5db0c4816802e 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -44,6 +44,7 @@ try { // install CLI const CLI_PACKAGE = 'react-native-cli'; if (!argv['skip-cli-install']) { + describe('Instal react-native-cli'); if (exec(`yarn global add ${CLI_PACKAGE}`).code) { echo('Could not install react-native-cli globally.'); echo('Run with --skip-cli-install to skip this step'); @@ -53,6 +54,7 @@ try { } if (argv.android) { + describe('Compile Android binaries'); if ( exec( './gradlew :ReactAndroid:installArchives -Pjobs=1 -Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError"', @@ -65,6 +67,7 @@ try { } if (argv.js) { + describe('Install Flow'); if ( tryExecNTimes( () => { @@ -81,6 +84,7 @@ try { } } + describe('Create react-native package'); if (exec('npm pack').code) { echo('Failed to pack react-native'); exitCode = 1; @@ -90,12 +94,16 @@ try { const PACKAGE = path.join(ROOT, 'react-native-*.tgz'); cd(TEMP); - echo('Creating EndToEndTest React Native app'); + describe('Create EndToEndTest React Native app'); if ( tryExecNTimes( () => { - return exec(`react-native init EndToEndTest --version ${PACKAGE} --npm`) - .code; + return exec( + `${path.join( + ROOT, + '/node_modules/.bin/react-native', + )} init EndToEndTest --version ${PACKAGE} --npm`, + ).code; }, numberOfRetries, () => { @@ -116,9 +124,10 @@ try { cp(RN_POLYFILLS, 'EndToEndTest/.'); cd('EndToEndTest'); - echo('Installing React Native package'); + describe('Install React Native package'); exec(`npm install ${PACKAGE}`); - echo('Installing node_modules'); + + describe('Install node_modules'); if ( tryExecNTimes( () => { @@ -135,8 +144,7 @@ try { } if (argv.android) { - describe('Executing Android end-to-end tests'); - echo('Installing end-to-end framework'); + describe('Install end-to-end framework'); if ( tryExecNTimes( () => @@ -154,10 +162,11 @@ try { } cp(`${SCRIPTS}/android-e2e-test.js`, 'android-e2e-test.js'); cd('android'); - echo('Downloading Maven deps'); + describe('Download Maven deps'); exec('./gradlew :app:copyDownloadableDepsToLibs'); cd('..'); + describe('Generate key'); exec('rm android/app/debug.keystore'); if ( exec( @@ -169,18 +178,18 @@ try { throw Error(exitCode); } - echo(`Starting appium server, ${APPIUM_PID}`); + describe(`Start appium server, ${APPIUM_PID}`); const appiumProcess = spawn('node', ['./node_modules/.bin/appium']); APPIUM_PID = appiumProcess.pid; - echo('Building the app'); - if (exec('react-native run-android').code) { + describe('Build the app'); + if (exec('./node_modules/.bin/react-native run-android').code) { echo('could not execute react-native run-android'); exitCode = 1; throw Error(exitCode); } - echo(`Starting packager server, ${SERVER_PID}`); + describe(`Start packager server, ${SERVER_PID}`); // shelljs exec('', {async: true}) does not emit stdout events, so we rely on good old spawn const packagerProcess = spawn('yarn', ['start', '--max-workers 1'], { env: process.env, @@ -207,11 +216,11 @@ try { if (argv.ios || argv.tvos) { var iosTestType = argv.tvos ? 'tvOS' : 'iOS'; - describe('Executing ' + iosTestType + ' end-to-end tests'); cd('ios'); // shelljs exec('', {async: true}) does not emit stdout events, so we rely on good old spawn const packagerEnv = Object.create(process.env); packagerEnv.REACT_NATIVE_MAX_WORKERS = 1; + describe('Start packager server'); const packagerProcess = spawn('yarn', ['start'], { stdio: 'inherit', env: packagerEnv, @@ -222,9 +231,11 @@ try { exec( 'response=$(curl --write-out %{http_code} --silent --output /dev/null localhost:8081/index.bundle?platform=ios&dev=true)', ); - echo(`Starting packager server, ${SERVER_PID}`); - echo('Running pod install'); + echo(`Packager server up and running, ${SERVER_PID}`); + + describe('Install CocoaPod dependencies'); exec('pod install'); + describe('Test: ' + iosTestType + ' end-to-end test'); if ( tryExecNTimes( @@ -259,7 +270,7 @@ try { '--report', 'junit', '--output', - `"~/react-native/reports/junit/${iosTestType}-e2e/results.xml"`, + `"~/reports/junit/${iosTestType}-e2e/results.xml"`, ].join(' ') + ' && exit ${PIPESTATUS[0]}', ).code; @@ -277,12 +288,11 @@ try { } if (argv.js) { - describe('Executing JavaScript end-to-end tests'); // Check the packager produces a bundle (doesn't throw an error) describe('Test: Verify packager can generate an Android bundle'); if ( exec( - 'react-native bundle --max-workers 1 --platform android --dev true --entry-file index.js --bundle-output android-bundle.js', + './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output android-bundle.js --platform android', ).code ) { echo('Could not build Android bundle'); @@ -292,7 +302,7 @@ try { describe('Test: Verify packager can generate an iOS bundle'); if ( exec( - 'react-native --max-workers 1 bundle --platform ios --dev true --entry-file index.js --bundle-output ios-bundle.js', + './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output ios-bundle.js --platform ios', ).code ) { echo('Could not build iOS bundle'); @@ -308,6 +318,7 @@ try { } exitCode = 0; } finally { + describe('Clean up'); if (SERVER_PID) { echo(`Killing packager ${SERVER_PID}`); exec(`kill -9 ${SERVER_PID}`); From 99bb710617ed6c0e076e6283e3cf4e107a4ea05e Mon Sep 17 00:00:00 2001 From: Dan Nguyen Date: Thu, 30 May 2019 15:16:14 -0700 Subject: [PATCH 031/330] Revert D15495065: Add method to get a segment path without injecting it in the VM Differential Revision: D15495065 Original commit changeset: 6537100d8b6d fbshipit-source-id: fee8319eaa5461f11ee4ea8d3b9d25e211beb2a8 --- .../SegmentFetcher/NativeSegmentFetcher.js | 5 -- Libraries/Core/setUpSegmentFetcher.js | 47 ++----------------- 2 files changed, 3 insertions(+), 49 deletions(-) diff --git a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js index 765b8ef0e07ef3..38319e03456d68 100644 --- a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js +++ b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js @@ -18,11 +18,6 @@ export interface Spec extends TurboModule { options: Object, // flowlint-line unclear-type: off callback: (error: ?Object) => void, // flowlint-line unclear-type: off ) => void; - +getSegment?: ( - segmentId: number, - options: Object, // flowlint-line unclear-type: off - callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off - ) => void; } export default TurboModuleRegistry.getEnforcing('SegmentFetcher'); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js index 3d811535ce38ee..dd182a69c91bb7 100644 --- a/Libraries/Core/setUpSegmentFetcher.js +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -9,20 +9,13 @@ */ 'use strict'; -export type FetchSegmentFunction = typeof __fetchSegment; -export type GetSegmentFunction = typeof __getSegment; - /** * Set up SegmentFetcher. * You can use this module directly, or just require InitializeCore. */ - -function __fetchSegment( +global.__fetchSegment = function( segmentId: number, - options: {| - +otaBuildNumber: ?string, - +requestedModuleName?: ?string, - |}, + options: {|+otaBuildNumber: ?string|}, callback: (?Error) => void, ) { const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') @@ -40,38 +33,4 @@ function __fetchSegment( callback(null); }, ); -} - -global.__fetchSegment = __fetchSegment; - -function __getSegment( - segmentId: number, - options: {| - +otaBuildNumber: ?string, - +requestedModuleName?: ?string, - |}, - callback: (?Error, ?string) => void, -) { - const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') - .default; - - if (!SegmentFetcher.getSegment) { - throw new Error('SegmentFetcher.getSegment must be defined'); - } - - SegmentFetcher.getSegment( - segmentId, - options, - (errorObject: ?{message: string, code: string}, path: ?string) => { - if (errorObject) { - const error = new Error(errorObject.message); - (error: any).code = errorObject.code; // flowlint-line unclear-type: off - callback(error); - } - - callback(null, path); - }, - ); -} - -global.__getSegment = __getSegment; +}; From 7fb02bd90884f0a717e8151d4d30767fe38392c1 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Thu, 30 May 2019 15:56:55 -0700 Subject: [PATCH 032/330] Rename onAccessibilityAction event on Android Summary: D15391408 (https://github.com/facebook/react-native/pull/24695) added a new event type with the registration name 'onAccessibilityAction' on Android, using the key 'performAction'. On iOS the same event uses the key 'topAccessibilityAction', which caused a runtime error after I started registering both using the unified JS view config in D15488008. This diff changes Android to use the same name as iOS since the convention is to start with 'top'. Reviewed By: cpojer Differential Revision: D15542623 fbshipit-source-id: c339621d2b4d3e1700feb5419ae3e3af8b185ca8 --- .../main/java/com/facebook/react/uimanager/BaseViewManager.java | 2 +- .../facebook/react/uimanager/ReactAccessibilityDelegate.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 524a4bf60c084e..0e68825e67ed16 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -376,7 +376,7 @@ protected void onAfterUpdateTransaction(@Nonnull T view) { @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return MapBuilder.builder() - .put("performAction", MapBuilder.of("registrationName", "onAccessibilityAction")) + .put("topAccessibilityAction", MapBuilder.of("registrationName", "onAccessibilityAction")) .build(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index 481f2e2821d669..332114fca6a14d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -183,7 +183,7 @@ public boolean performAccessibilityAction(View host, int action, Bundle args) { ReactContext reactContext = (ReactContext)host.getContext(); reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( host.getId(), - "performAction", + "topAccessibilityAction", event); return true; } From 060a3ea3bf7bb1f77dbb29a6fe23e2e823fbc52b Mon Sep 17 00:00:00 2001 From: Ram N Date: Thu, 30 May 2019 17:24:27 -0700 Subject: [PATCH 033/330] Delete Start/Stop Profiler from Dev Menu in Android Reviewed By: mdvacca Differential Revision: D10473627 fbshipit-source-id: eec61903f0a7abd0757aed0750d4bd828e4887bc --- .../com/facebook/react/DebugCorePackage.java | 13 +- .../devsupport/DevSupportManagerImpl.java | 67 +------- .../react/devsupport/JSCSamplingProfiler.java | 148 ------------------ .../main/res/devsupport/values/strings.xml | 1 - 4 files changed, 2 insertions(+), 227 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java b/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java index 1ecb2d5557d39f..e40b61a93c698c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java @@ -10,9 +10,8 @@ import com.facebook.react.bridge.ModuleSpec; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.devsupport.JSCSamplingProfiler; -import com.facebook.react.devsupport.JSDevSupport; import com.facebook.react.devsupport.JSCHeapCapture; +import com.facebook.react.devsupport.JSDevSupport; import com.facebook.react.module.annotations.ReactModuleList; import com.facebook.react.module.model.ReactModuleInfoProvider; import java.util.ArrayList; @@ -27,7 +26,6 @@ @ReactModuleList( nativeModules = { JSCHeapCapture.class, - JSCSamplingProfiler.class, JSDevSupport.class, } ) @@ -48,15 +46,6 @@ public NativeModule get() { return new JSCHeapCapture(reactContext); } })); - moduleSpecList.add( - ModuleSpec.nativeModuleSpec( - JSCSamplingProfiler.class, - new Provider() { - @Override - public NativeModule get() { - return new JSCSamplingProfiler(reactContext); - } - })); return moduleSpecList; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java index 7443b4e3d2bb7e..5938ce067ec761 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -150,39 +150,6 @@ private enum ErrorType { private @Nullable Map mCustomPackagerCommandHandlers; - private static class JscProfileTask extends AsyncTask { - private static final MediaType JSON = - MediaType.parse("application/json; charset=utf-8"); - - private final String mSourceUrl; - - private JscProfileTask(String sourceUrl) { - mSourceUrl = sourceUrl; - } - - @Override - protected Void doInBackground(String... jsonData) { - try { - String jscProfileUrl = - Uri.parse(mSourceUrl).buildUpon() - .path("/jsc-profile") - .query(null) - .build() - .toString(); - OkHttpClient client = new OkHttpClient(); - for (String json: jsonData) { - RequestBody body = RequestBody.create(JSON, json); - Request request = - new Request.Builder().url(jscProfileUrl).post(body).build(); - client.newCall(request).execute(); - } - } catch (IOException e) { - FLog.e(ReactConstants.TAG, "Failed not talk to server", e); - } - return null; - } - } - public DevSupportManagerImpl( Context applicationContext, ReactInstanceManagerDevHelper reactInstanceManagerHelper, @@ -467,10 +434,8 @@ public void onOptionSelected() { } }); if (mDevSettings.isNuclideJSDebugEnabled()) { - // The concatenation is applied directly here because XML isn't emoji-friendly String nuclideJsDebugMenuItemTitle = - mApplicationContext.getString(R.string.catalyst_debugjs_nuclide) - + EMOJI_HUNDRED_POINTS_SYMBOL; + mApplicationContext.getString(R.string.catalyst_debugjs_nuclide); options.put( nuclideJsDebugMenuItemTitle, new DevOptionHandler() { @@ -484,9 +449,6 @@ public void onOptionSelected() { mDevSettings.isRemoteJSDebugEnabled() ? mApplicationContext.getString(R.string.catalyst_debugjs_off) : mApplicationContext.getString(R.string.catalyst_debugjs); - if (mDevSettings.isNuclideJSDebugEnabled()) { - remoteJsDebugMenuItemTitle += EMOJI_FACE_WITH_NO_GOOD_GESTURE; - } options.put( remoteJsDebugMenuItemTitle, new DevOptionHandler() { @@ -549,14 +511,6 @@ public void onOptionSelected() { mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled()); } }); - options.put( - mApplicationContext.getString(R.string.catalyst_poke_sampling_profiler), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - handlePokeSamplingProfiler(); - } - }); options.put( mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() { @Override @@ -878,25 +832,6 @@ public void onFailure(JSCHeapCapture.CaptureException error) { }); } - private void handlePokeSamplingProfiler() { - try { - List pokeResults = JSCSamplingProfiler.poke(60000); - for (String result : pokeResults) { - Toast.makeText( - mCurrentContext, - result == null - ? "Started JSC Sampling Profiler" - : "Stopped JSC Sampling Profiler", - Toast.LENGTH_LONG).show(); - new JscProfileTask(getSourceUrl()).executeOnExecutor( - AsyncTask.THREAD_POOL_EXECUTOR, - result); - } - } catch (JSCSamplingProfiler.ProfilerException e) { - showNewJavaError(e.getMessage(), e); - } - } - private void updateLastErrorInfo( @Nullable final String message, final StackFrame[] stack, diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java deleted file mode 100644 index 59c05dcf4f2234..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.devsupport; - -import javax.annotation.Nullable; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.module.annotations.ReactModule; - -// This module is being called only by Java via the static method "poke" that -// requires it to alreay be initialized, thus we eagerly initialize this module -@ReactModule(name = "JSCSamplingProfiler", needsEagerInit = true) -public class JSCSamplingProfiler extends ReactContextBaseJavaModule { - public interface SamplingProfiler extends JavaScriptModule { - void poke(int token); - } - - public static class ProfilerException extends Exception { - ProfilerException(String message) { - super(message); - } - } - - private @Nullable SamplingProfiler mSamplingProfiler; - private boolean mOperationInProgress; - private int mOperationToken; - private @Nullable String mOperationError; - private @Nullable String mSamplingProfilerResult; - - private static final HashSet sRegisteredDumpers = - new HashSet<>(); - - private static synchronized void registerSamplingProfiler( - JSCSamplingProfiler dumper) { - if (sRegisteredDumpers.contains(dumper)) { - throw new RuntimeException( - "a JSCSamplingProfiler registered more than once"); - } - sRegisteredDumpers.add(dumper); - } - - private static synchronized void unregisterSamplingProfiler( - JSCSamplingProfiler dumper) { - sRegisteredDumpers.remove(dumper); - } - - public static synchronized List poke(long timeout) - throws ProfilerException { - LinkedList results = new LinkedList<>(); - if (sRegisteredDumpers.isEmpty()) { - throw new ProfilerException("No JSC registered"); - } - - for (JSCSamplingProfiler dumper : sRegisteredDumpers) { - dumper.pokeHelper(timeout); - results.add(dumper.mSamplingProfilerResult); - } - return results; - } - - public JSCSamplingProfiler(ReactApplicationContext reactContext) { - super(reactContext); - mSamplingProfiler = null; - mOperationInProgress = false; - mOperationToken = 0; - mOperationError = null; - mSamplingProfilerResult = null; - } - - private synchronized void pokeHelper(long timeout) throws ProfilerException { - if (mSamplingProfiler == null) { - throw new ProfilerException("SamplingProfiler.js module not connected"); - } - mSamplingProfiler.poke(getOperationToken()); - waitForOperation(timeout); - } - - private int getOperationToken() throws ProfilerException { - if (mOperationInProgress) { - throw new ProfilerException("Another operation already in progress."); - } - mOperationInProgress = true; - return ++mOperationToken; - } - - private void waitForOperation(long timeout) throws ProfilerException { - try { - wait(timeout); - } catch (InterruptedException e) { - throw new ProfilerException( - "Waiting for heap capture failed: " + e.getMessage()); - } - - if (mOperationInProgress) { - mOperationInProgress = false; - throw new ProfilerException("heap capture timed out."); - } - - if (mOperationError != null) { - throw new ProfilerException(mOperationError); - } - } - - @ReactMethod - public synchronized void operationComplete( - int token, String result, String error) { - if (token == mOperationToken) { - mOperationInProgress = false; - mSamplingProfilerResult = result; - mOperationError = error; - this.notify(); - } else { - throw new RuntimeException("Completed operation is not in progress."); - } - } - - @Override - public String getName() { - return "JSCSamplingProfiler"; - } - - @Override - public void initialize() { - super.initialize(); - mSamplingProfiler = - getReactApplicationContext().getJSModule(SamplingProfiler.class); - registerSamplingProfiler(this); - } - - @Override - public void onCatalystInstanceDestroy() { - super.onCatalystInstanceDestroy(); - unregisterSamplingProfiler(this); - mSamplingProfiler = null; - } -} diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml index 29411de6e7aa8f..125f48d6195af7 100644 --- a/ReactAndroid/src/main/res/devsupport/values/strings.xml +++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml @@ -20,7 +20,6 @@ Capture Heap Dismiss\n(ESC) Reload\n(R,\u00A0R) - Start/Stop Sampling Profiler Copy\n Report Loading from %1$s… From 739651afa1c0b90bf0fb75d9c09047645ff55388 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 30 May 2019 18:47:10 -0700 Subject: [PATCH 034/330] RN: Simplify Context Creation (Android) Summary: Every call site is either already using `createReactContextInBackground` correctly or guarding the invocation using `hasStartedCreatingInitialContext`. This is an unnecessary and overly complex dance that can be simplified. This revision simplifies the use of `createReactContextInBackground` by integrating the check. This is not a breaking change. Reviewed By: zackargyle, mdvacca Differential Revision: D15566632 fbshipit-source-id: 7b50285c9ac6776d1297d2c9c53dff208851b722 --- .../facebook/react/HeadlessJsTaskService.java | 4 +--- .../com/facebook/react/ReactInstanceManager.java | 16 +++++----------- .../java/com/facebook/react/ReactRootView.java | 4 +--- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java b/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java index cf809e9eb17435..c527167cf3db92 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java +++ b/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java @@ -108,9 +108,7 @@ public void onReactContextInitialized(ReactContext reactContext) { reactInstanceManager.removeReactInstanceEventListener(this); } }); - if (!reactInstanceManager.hasStartedCreatingInitialContext()) { - reactInstanceManager.createReactContextInBackground(); - } + reactInstanceManager.createReactContextInBackground(); } else { invokeStartTask(reactContext, taskConfig); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index e9513a059352bc..0926cf7efb37ce 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -325,23 +325,17 @@ private static void initializeSoLoaderIfNecessary(Context applicationContext) { /** * Trigger react context initialization asynchronously in a background async task. This enables * applications to pre-load the application JS, and execute global code before - * {@link ReactRootView} is available and measured. This should only be called the first time the - * application is set up, which is enforced to keep developers from accidentally creating their - * application multiple times without realizing it. + * {@link ReactRootView} is available and measured. * * Called from UI thread. */ @ThreadConfined(UI) public void createReactContextInBackground() { Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()"); - Assertions.assertCondition( - !mHasStartedCreatingInitialContext, - "createReactContextInBackground should only be called when creating the react " + - "application for the first time. When reloading JS, e.g. from a new file, explicitly" + - "use recreateReactContextInBackground"); - - mHasStartedCreatingInitialContext = true; - recreateReactContextInBackgroundInner(); + if (!mHasStartedCreatingInitialContext) { + mHasStartedCreatingInitialContext = true; + recreateReactContextInBackgroundInner(); + } } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 3cf5a45d3a85fb..1a98fd22479e14 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -394,9 +394,7 @@ public void startReactApplication( // TODO initialize surface here } - if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { - mReactInstanceManager.createReactContextInBackground(); - } + mReactInstanceManager.createReactContextInBackground(); attachToReactInstanceManager(); From a0879ce49f11812e478d0cda2827f36f325cf972 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Thu, 30 May 2019 21:01:55 -0700 Subject: [PATCH 035/330] Add spec for UIManager (#24902) Summary: part of #24875. Because some of the methods are rewriteable, I dropped the `+` from the signature, this doesn't feel right to me, but I am not sure if the codegen requires that. If it does, it will probably be better to extend the spec and allow those specific methods to be overriden in a UIManager.js interface. Thoughts on that fkgozali or RSNara? ## Changelog [General] [Added] - Add TM spec for UIManager Pull Request resolved: https://github.com/facebook/react-native/pull/24902 Reviewed By: hramos Differential Revision: D15551356 Pulled By: fkgozali fbshipit-source-id: 076c4ce635aa7ea41e21cbd67c47ecd562fc320d --- .../AccessibilityInfo.android.js | 2 +- Libraries/ReactNative/NativeUIManager.js | 122 ++++++++++++++++ Libraries/ReactNative/UIManager.js | 131 +++++++++++------- Libraries/ReactNative/UIManagerStatTracker.js | 4 +- .../getNativeComponentAttributes.js | 7 +- 5 files changed, 213 insertions(+), 53 deletions(-) create mode 100644 Libraries/ReactNative/NativeUIManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index ff9a7329a56c87..5c9ab848d2ecff 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -139,7 +139,7 @@ const AccessibilityInfo = { setAccessibilityFocus: function(reactTag: number): void { UIManager.sendAccessibilityEvent( reactTag, - UIManager.AccessibilityEventTypes.typeViewFocused, + UIManager.getConstants().AccessibilityEventTypes.typeViewFocused, ); }, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js new file mode 100644 index 00000000000000..9eb60e68194b81 --- /dev/null +++ b/Libraries/ReactNative/NativeUIManager.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => Object; + +getConstantsForViewManager: (viewManagerName: string) => Object; + +getDefaultEventTypes: () => Array; + +playTouchSound: () => void; + +lazilyLoadView: (name: string) => Object; // revisit return + +createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + +updateView: (reactTag: number, viewName: string, props: Object) => void; + +focus: (reactTag: ?number) => void; + +blur: (reactTag: ?number) => void; + +findSubviewIn: ( + reactTag: ?number, + point: [number, number], + callback: ( + nativeViewTag: number, + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +dispatchViewManagerCommand: ( + reactTag: ?number, + commandID: number, + commandArgs: ?Array, // is this best? + ) => void; + +measure: ( + reactTag: ?number, + callback: ( + left: number, + top: number, + width: number, + height: number, + pageX: number, + pageY: number, + ) => void, + ) => void; + +measureInWindow: ( + reactTag: ?number, + callback: (x: number, y: number, width: number, height: number) => void, + ) => void; + +viewIsDescendantOf: ( + reactTag: ?number, + ancestorReactTag: ?number, + callback: (result: Array) => void, + ) => void; + +measureLayout: ( + reactTag: ?number, + ancestorReactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +measureLayoutRelativeToParent: ( + reactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +setJSResponder: (reactTag: ?number, blockNativeResponder: boolean) => void; + +clearJSResponder: () => void; + +configureNextLayoutAnimation: ( + config: Object, + callback: () => void, // check what is returned here + errorCallback: (error: Object) => void, + ) => void; + +removeSubviewsFromContainerWithID: (containerID: number) => void; + +replaceExistingNonRootView: ( + reactTag: ?number, + newReactTag: ?number, + ) => void; + +setChildren: (containerTag: ?number, reactTags: Array) => void; + +manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; + + // Android only + +setLayoutAnimationEnabledExperimental: (enabled: boolean) => void; + +sendAccessibilityEvent: (reactTag: ?number, eventType: number) => void; + +showPopupMenu: ( + reactTag: ?number, + items: Array, + error: (error: Object) => void, + success: (event: string, selected?: number) => void, + ) => void; + +dismissPopupMenu: () => void; +} + +export default TurboModuleRegistry.getEnforcing('UIManager'); diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index cf7f8edbdbb839..234732bfe1db2c 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict-local + * @flow * @format */ 'use strict'; @@ -14,58 +14,94 @@ const Platform = require('../Utilities/Platform'); const UIManagerProperties = require('./UIManagerProperties'); const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty'); -const invariant = require('invariant'); -const {UIManager} = NativeModules; +import NativeUIManager from './NativeUIManager'; +import type {Spec} from './NativeUIManager'; + const viewManagerConfigs = {}; -invariant( - UIManager, - 'UIManager is undefined. The native module config is probably incorrect.', -); +interface UIManagerJSInterface extends Spec { + +getViewManagerConfig: (viewManagerName: string) => Object; + // The following are not marked read-only due to logic in UIManagerStatTracker. + createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + updateView: (reactTag: number, viewName: string, props: Object) => void; + manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; +} const triedLoadingConfig = new Set(); -UIManager.getViewManagerConfig = function(viewManagerName: string) { - if ( - viewManagerConfigs[viewManagerName] === undefined && - UIManager.getConstantsForViewManager - ) { - try { - viewManagerConfigs[ - viewManagerName - ] = UIManager.getConstantsForViewManager(viewManagerName); - } catch (e) { - viewManagerConfigs[viewManagerName] = null; - } - } - const config = viewManagerConfigs[viewManagerName]; - if (config) { - return config; +let NativeUIManagerConstants = {}; +let isNativeUIManagerConstantsSet = false; +function getConstants(): Object { + if (!isNativeUIManagerConstantsSet) { + NativeUIManagerConstants = NativeUIManager.getConstants(); + isNativeUIManagerConstantsSet = true; } + return NativeUIManagerConstants; +} + +const UIManagerJS: UIManagerJSInterface = { + ...NativeUIManager, + getConstants(): Object { + return getConstants(); + }, + getViewManagerConfig: function(viewManagerName: string) { + if ( + viewManagerConfigs[viewManagerName] === undefined && + NativeUIManager.getConstantsForViewManager + ) { + try { + viewManagerConfigs[ + viewManagerName + ] = NativeUIManager.getConstantsForViewManager(viewManagerName); + } catch (e) { + viewManagerConfigs[viewManagerName] = null; + } + } - // If we're in the Chrome Debugger, let's not even try calling the sync - // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { + const config = viewManagerConfigs[viewManagerName]; + if (config) { return config; } - } - if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) { - const result = UIManager.lazilyLoadView(viewManagerName); - triedLoadingConfig.add(viewManagerName); - if (result.viewConfig) { - UIManager[viewManagerName] = result.viewConfig; - lazifyViewManagerConfig(viewManagerName); + // If we're in the Chrome Debugger, let's not even try calling the sync + // method. + if (__DEV__) { + if (!global.nativeCallSyncHook) { + return config; + } } - } - return viewManagerConfigs[viewManagerName]; + if ( + NativeUIManager.lazilyLoadView && + !triedLoadingConfig.has(viewManagerName) + ) { + const result = NativeUIManager.lazilyLoadView(viewManagerName); + triedLoadingConfig.add(viewManagerName); + if (result.viewConfig) { + getConstants()[viewManagerName] = result.viewConfig; + lazifyViewManagerConfig(viewManagerName); + } + } + + return viewManagerConfigs[viewManagerName]; + }, }; function lazifyViewManagerConfig(viewName) { - const viewConfig = UIManager[viewName]; + const viewConfig = getConstants()[viewName]; if (viewConfig.Manager) { viewManagerConfigs[viewName] = viewConfig; defineLazyObjectProperty(viewConfig, 'Constants', { @@ -106,10 +142,10 @@ function lazifyViewManagerConfig(viewName) { * namespace instead of UIManager, unlike Android. */ if (Platform.OS === 'ios') { - Object.keys(UIManager).forEach(viewName => { + Object.keys(getConstants()).forEach(viewName => { lazifyViewManagerConfig(viewName); }); -} else if (UIManager.ViewManagerNames) { +} else if (getConstants().ViewManagerNames) { // We want to add all the view managers to the UIManager. // However, the way things are set up, the list of view managers is not known at compile time. // As Prepack runs at compile it, it cannot process this loop. @@ -120,13 +156,13 @@ if (Platform.OS === 'ios') { residual( 'void', (UIManager, defineLazyObjectProperty) => { - UIManager.ViewManagerNames.forEach(viewManagerName => { + UIManager.getConstants().ViewManagerNames.forEach(viewManagerName => { defineLazyObjectProperty(UIManager, viewManagerName, { get: () => UIManager.getConstantsForViewManager(viewManagerName), }); }); }, - UIManager, + NativeUIManager, defineLazyObjectProperty, ); @@ -135,27 +171,28 @@ if (Platform.OS === 'ios') { // so that any accesses to unknown properties along the global code will fail // when Prepack encounters them. if (global.__makePartial) { - global.__makePartial(UIManager); + global.__makePartial(NativeUIManager); } } if (__DEV__) { - Object.keys(UIManager).forEach(viewManagerName => { + Object.keys(getConstants()).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { - viewManagerConfigs[viewManagerName] = UIManager[viewManagerName]; + viewManagerConfigs[viewManagerName] = getConstants()[viewManagerName]; } - defineLazyObjectProperty(UIManager, viewManagerName, { + defineLazyObjectProperty(NativeUIManager, viewManagerName, { get: () => { console.warn( `Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` + `is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`, ); - return UIManager.getViewManagerConfig(viewManagerName); + + return UIManagerJS.getViewManagerConfig(viewManagerName); }, }); } }); } -module.exports = UIManager; +module.exports = UIManagerJS; diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js index ec1494c53b4390..85aaa6ba7707a7 100644 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ b/Libraries/ReactNative/UIManagerStatTracker.js @@ -52,8 +52,8 @@ const UIManagerStatTracker = { remove, ) { incStat('manageChildren', 1); - incStat('move', Object.keys(moveFrom || []).length); - incStat('remove', Object.keys(remove || []).length); + incStat('move', moveFrom.length); + incStat('remove', remove.length); manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove); }; }, diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index bf08c389eb8753..85a347bea1f358 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -96,17 +96,18 @@ function attachDefaultEventTypes(viewConfig: any) { // This is supported on UIManager platforms (ex: Android), // as lazy view managers are not implemented for all platforms. // See [UIManager] for details on constants and implementations. - if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) { + const constants = UIManager.getConstants(); + if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) { // Lazy view managers enabled. viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); } else { viewConfig.bubblingEventTypes = merge( viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, + constants.genericBubblingEventTypes, ); viewConfig.directEventTypes = merge( viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, + constants.genericDirectEventTypes, ); } } From 85252a6cac044872e80f35fb3ab1c198d92cbf21 Mon Sep 17 00:00:00 2001 From: Jarvis Luong Date: Thu, 30 May 2019 21:01:55 -0700 Subject: [PATCH 036/330] Add spec for DevSettings (#25084) Summary: Part of #24875, adds a spec for DevSettings. ## Changelog [General] [Added] - TM spec for DevSettings Pull Request resolved: https://github.com/facebook/react-native/pull/25084 Reviewed By: hramos Differential Revision: D15558093 Pulled By: fkgozali fbshipit-source-id: 3adcb640a6ad80c84c831905bda114e27177f1fe --- .../NativeModules/specs/NativeDevSettings.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Libraries/NativeModules/specs/NativeDevSettings.js diff --git a/Libraries/NativeModules/specs/NativeDevSettings.js b/Libraries/NativeModules/specs/NativeDevSettings.js new file mode 100644 index 00000000000000..9a53a0db7905e0 --- /dev/null +++ b/Libraries/NativeModules/specs/NativeDevSettings.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +reload: () => void; + +setHotLoadingEnabled: (isHotLoadingEnabled: boolean) => void; + +setIsDebuggingRemotely: (isDebuggingRemotelyEnabled: boolean) => void; + +setLiveReloadEnabled: (isLiveReloadEnabled: boolean) => void; + +setProfilingEnabled: (isProfilingEnabled: boolean) => void; + +toggleElementInspector: () => void; + + // iOS only. + +setIsShakeToShowDevMenuEnabled: (enabled: boolean) => void; +} + +export default TurboModuleRegistry.getEnforcing('DevSettings'); From 8db4de41e41f1983ac71f618fa29ce70e3d09eb5 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 30 May 2019 21:39:30 -0700 Subject: [PATCH 037/330] TM Spec: relax PermissionsAndroid enforcement Summary: Some modules accessed PermissionsAndroid even in iOS, causing redbox. Let's relax the enforcement, then invariant() on the callsites instead. Reviewed By: yungsters Differential Revision: D15572716 fbshipit-source-id: 4a2edea608ab27727e88f0f246ecb9cdcf5a5329 --- .../NativePermissionsAndroid.js | 2 +- .../PermissionsAndroid/PermissionsAndroid.js | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index 025f9af18419b1..4212164d8baf83 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -56,4 +56,4 @@ export interface Spec extends TurboModule { ) => Promise<{[permission: PermissionType]: PermissionStatus}>; } -export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); +export default TurboModuleRegistry.get('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 1b414e71165a29..427fb21c8a1f88 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -11,10 +11,11 @@ 'use strict'; import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; -const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); import NativePermissionsAndroid from './NativePermissionsAndroid'; +import invariant from 'invariant'; + import type { PermissionStatus, PermissionType, @@ -90,6 +91,11 @@ class PermissionsAndroid { return Promise.resolve(false); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -106,6 +112,12 @@ class PermissionsAndroid { ); return Promise.resolve(false); } + + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -158,6 +170,11 @@ class PermissionsAndroid { return Promise.resolve(this.RESULTS.DENIED); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + if (rationale) { const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, @@ -197,6 +214,11 @@ class PermissionsAndroid { return Promise.resolve({}); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From 796e9b0e3746ec8e58dcae19750bc1672ca93605 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 30 May 2019 22:38:59 -0700 Subject: [PATCH 038/330] RN: Debug Menu Cleanup (iOS) Summary: Addresses a number of pieces of feedback regarding the debug menu. - Simplify labels for the debugger actions (e.g. no "remote", no emoji). - Reorder actions so that modal items are generally lower. - Changed "Toggle Inspector" to "Show/Hide Inspector". - Renamed "Live Reloading" to "Reload-on-Save". - Hide disabled debug items when profiling is enabled. - Changed "Start Systrace" to "Systrace Unavailable" when debugging. - Renamed "Change packager location" to "Configure Bundler". - Revised nomenclature in "Configure Bundler" menu to be clearer. - Removed extraneous debug menu title. - Consistently refer to HMR as "Hot Reloading". Changelog: [iOS] [Changed] - Cleaned up debug menu. Reviewed By: axe-fb Differential Revision: D15548628 fbshipit-source-id: 26b2ddca8280d1f6f8ff904439b403600e98a3b3 --- Libraries/Utilities/HMRClient.js | 4 +- React/DevSupport/RCTDevMenu.m | 125 ++++++++++++++++--------------- 2 files changed, 65 insertions(+), 64 deletions(-) diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js index eb34d2d83ecc8d..f901778b659a39 100644 --- a/Libraries/Utilities/HMRClient.js +++ b/Libraries/Utilities/HMRClient.js @@ -45,7 +45,7 @@ const HMRClient = { const hmrClient = new MetroHMRClient(wsUrl); hmrClient.on('connection-error', e => { - let error = `Hot loading isn't working because it cannot connect to the development server. + let error = `Hot reloading isn't working because it cannot connect to the development server. Try the following to fix the issue: - Ensure that the packager server is running and available on the same network`; @@ -70,7 +70,7 @@ Error: ${e.message}`; }); hmrClient.on('update-start', () => { - HMRLoadingView.showMessage('Hot Loading...'); + HMRLoadingView.showMessage('Hot Reloading...'); }); hmrClient.on('update', () => { diff --git a/React/DevSupport/RCTDevMenu.m b/React/DevSupport/RCTDevMenu.m index 140be91dd98fa5..a57c4222cfdde0 100644 --- a/React/DevSupport/RCTDevMenu.m +++ b/React/DevSupport/RCTDevMenu.m @@ -210,56 +210,62 @@ - (void)setDefaultJSBundle { [bridge reload]; }]]; - if (devSettings.isNuclideDebuggingAvailable) { - [items addObject:[RCTDevMenuItem buttonItemWithTitle:[NSString stringWithFormat:@"Debug JS in Nuclide %@", @"\U0001F4AF"] handler:^{ -#if RCT_ENABLE_INSPECTOR - [RCTInspectorDevServerHelper attachDebugger:@"ReactNative" withBundleURL:bridge.bundleURL withView: RCTPresentedViewController()]; -#endif - }]]; - } + if (!devSettings.isProfilingEnabled) { + if (!devSettings.isRemoteDebuggingAvailable) { + [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Debugger Unavailable" handler:^{ + NSString *message = RCTTurboModuleEnabled() ? + @"Debugging is not currently supported when TurboModule is enabled." : + @"Include the RCTWebSocket library to enable JavaScript debugging."; + UIAlertController *alertController = [UIAlertController + alertControllerWithTitle:@"Debugger Unavailable" + message:message + preferredStyle:UIAlertControllerStyleAlert]; + __weak typeof(alertController) weakAlertController = alertController; + [alertController addAction: + [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action){ + [weakAlertController dismissViewControllerAnimated:YES completion:nil]; + }]]; + [RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL]; + }]]; + } else { + [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ + if (devSettings.isNuclideDebuggingAvailable) { + return devSettings.isDebuggingRemotely ? @"Stop Chrome Debugger" : @"Debug with Chrome"; + } else { + return devSettings.isDebuggingRemotely ? @"Stop Debugging" : @"Debug"; + } + } handler:^{ + devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely; + }]]; + } - if (!devSettings.isRemoteDebuggingAvailable) { - [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Remote JS Debugger Unavailable" handler:^{ - NSString *message = RCTTurboModuleEnabled() ? - @"You cannot use remote JS debugging when TurboModule system is enabled" : - @"You need to include the RCTWebSocket library to enable remote JS debugging"; - UIAlertController *alertController = [UIAlertController - alertControllerWithTitle:@"Remote JS Debugger Unavailable" - message:message - preferredStyle:UIAlertControllerStyleAlert]; - __weak typeof(alertController) weakAlertController = alertController; - [alertController addAction: - [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action){ - [weakAlertController dismissViewControllerAnimated:YES completion:nil]; + if (devSettings.isNuclideDebuggingAvailable && !devSettings.isDebuggingRemotely) { + [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Debug with Nuclide" handler:^{ + #if RCT_ENABLE_INSPECTOR + [RCTInspectorDevServerHelper attachDebugger:@"ReactNative" withBundleURL:bridge.bundleURL withView: RCTPresentedViewController()]; + #endif }]]; - [RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL]; - }]]; - } else { - [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - NSString *title = devSettings.isDebuggingRemotely ? @"Stop Remote JS Debugging" : @"Debug JS Remotely"; - if (devSettings.isNuclideDebuggingAvailable) { - return [NSString stringWithFormat:@"%@ %@", title, @"\U0001F645"]; - } else { - return title; - } - } handler:^{ - devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely; - }]]; + } } + [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ + return devSettings.isElementInspectorShown ? @"Disable Inspector" : @"Enable Inspector"; + } handler:^{ + [devSettings toggleElementInspector]; + }]]; + if (devSettings.isLiveReloadAvailable) { [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return devSettings.isLiveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload"; - } handler:^{ - devSettings.isLiveReloadEnabled = !devSettings.isLiveReloadEnabled; - }]]; - [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return devSettings.isProfilingEnabled ? @"Stop Systrace" : @"Start Systrace"; + return devSettings.isDebuggingRemotely + ? @"Systrace Unavailable" + : devSettings.isProfilingEnabled + ? @"Stop Systrace" + : @"Start Systrace"; } handler:^{ if (devSettings.isDebuggingRemotely) { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Systrace Unavailable" - message:@"You need to stop remote JS debugging to enable Systrace" + message:@"Stop debugging to enable Systrace." preferredStyle:UIAlertControllerStyleAlert]; __weak typeof(alertController) weakAlertController = alertController; [alertController addAction: @@ -271,9 +277,15 @@ - (void)setDefaultJSBundle { devSettings.isProfilingEnabled = !devSettings.isProfilingEnabled; } }]]; + + [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ + return devSettings.isLiveReloadEnabled ? @"Disable Reload-on-Save" : @"Enable Reload-on-Save"; + } handler:^{ + devSettings.isLiveReloadEnabled = !devSettings.isLiveReloadEnabled; + }]]; } - if (_bridge.devSettings.isHotLoadingAvailable) { + if (devSettings.isHotLoadingAvailable) { [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ return devSettings.isHotLoadingEnabled ? @"Disable Hot Reloading" : @"Enable Hot Reloading"; } handler:^{ @@ -282,10 +294,10 @@ - (void)setDefaultJSBundle { } [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return @"Change packager location"; + return @"Configure Bundler"; } handler:^{ - UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"Change packager location" - message: @"Input packager IP, port and entrypoint" + UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"Configure Bundler" + message: @"Provide a custom bundler address, port, and entrypoint." preferredStyle:UIAlertControllerStyleAlert]; [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = @"0.0.0.0"; @@ -296,16 +308,13 @@ - (void)setDefaultJSBundle { [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = @"index"; }]; - [alertController addAction:[UIAlertAction actionWithTitle:@"Use bundled JS" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { - [weakSelf setDefaultJSBundle]; - }]]; - [alertController addAction:[UIAlertAction actionWithTitle:@"Use packager location" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { + [alertController addAction:[UIAlertAction actionWithTitle:@"Apply Changes" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { NSArray * textfields = alertController.textFields; UITextField * ipTextField = textfields[0]; UITextField * portTextField = textfields[1]; UITextField * bundleRootTextField = textfields[2]; NSString * bundleRoot = bundleRootTextField.text; - if(bundleRoot.length==0){ + if(bundleRoot.length == 0){ bundleRoot = @"index"; } if(ipTextField.text.length == 0 && portTextField.text.length == 0) { @@ -326,18 +335,15 @@ - (void)setDefaultJSBundle { [strongBridge reload]; } }]]; + [alertController addAction:[UIAlertAction actionWithTitle:@"Reset to Default" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { + [weakSelf setDefaultJSBundle]; + }]]; [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction *action) { return; }]]; [RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL]; }]]; - [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return @"Toggle Inspector"; - } handler:^{ - [devSettings toggleElementInspector]; - }]]; - [items addObjectsFromArray:_extraMenuItems]; return items; } @@ -348,15 +354,10 @@ - (void)setDefaultJSBundle { return; } - NSString *desc = _bridge.bridgeDescription; - if (desc.length == 0) { - desc = NSStringFromClass([_bridge class]); - } - NSString *title = [NSString stringWithFormat:@"React Native: Development (%@)", desc]; // On larger devices we don't have an anchor point for the action sheet UIAlertControllerStyle style = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? UIAlertControllerStyleActionSheet : UIAlertControllerStyleAlert; - _actionSheet = [UIAlertController alertControllerWithTitle:title - message:@"" + _actionSheet = [UIAlertController alertControllerWithTitle:nil + message:nil preferredStyle:style]; NSArray *items = [self _menuItemsToPresent]; From dac037d371f77963cfff3fc3acfcb8a8c955a3d2 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 30 May 2019 22:38:59 -0700 Subject: [PATCH 039/330] RN: Debug Menu Cleanup (Android) Summary: Addresses a number of pieces of feedback regarding the debug menu. - Simplify labels for the debugger actions (e.g. no "remote", no emoji). - Reorder actions so that modal items are generally lower. - Renamed "Live Reloading" to "Reload-on-Save". - Renamed "Dev Settings" to "Settings". Changelog: [Android] [Changed] - Cleaned up debug menu. Reviewed By: cpojer Differential Revision: D15553883 fbshipit-source-id: d30e8cd0804e010985c0cf40d443defc7c0710ac --- .../devsupport/DevLoadingViewController.java | 2 +- .../react/devsupport/DevServerHelper.java | 2 +- .../devsupport/DevSupportManagerImpl.java | 113 ++++++++++-------- .../main/res/devsupport/values/strings.xml | 36 +++--- 4 files changed, 82 insertions(+), 71 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java index d8f4f319aabe90..36b6eb07ec8af2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java @@ -81,7 +81,7 @@ public void showForRemoteJSEnabled() { return; } - showMessage(context.getString(R.string.catalyst_remotedbg_message)); + showMessage(context.getString(R.string.catalyst_debug_connecting)); } public void updateProgress(final @Nullable String status, final @Nullable Integer done, final @Nullable Integer total) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java index f7d9748c967d3e..2f70a32292ece7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -275,7 +275,7 @@ public boolean doSync() { @Override protected void onPostExecute(Boolean result) { if (!result) { - String message = context.getString(R.string.catalyst_debugjs_nuclide_failure); + String message = context.getString(R.string.catalyst_debug_nuclide_error); Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java index 5938ce067ec761..dfc241c51091fc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -422,46 +422,59 @@ public void showDevOptionsDialog() { LinkedHashMap options = new LinkedHashMap<>(); /* register standard options */ options.put( - mApplicationContext.getString(R.string.catalyst_reloadjs), + mApplicationContext.getString(R.string.catalyst_reload), + new DevOptionHandler() { + @Override + public void onOptionSelected() { + if (!mDevSettings.isJSDevModeEnabled() && mDevSettings.isHotModuleReplacementEnabled()) { + Toast.makeText( + mApplicationContext, + mApplicationContext.getString(R.string.catalyst_hot_reloading_auto_disable), + Toast.LENGTH_LONG).show(); + mDevSettings.setHotModuleReplacementEnabled(false); + } + handleReloadJS(); + } + }); + options.put( + mDevSettings.isNuclideJSDebugEnabled() + ? mDevSettings.isRemoteJSDebugEnabled() + ? mApplicationContext.getString(R.string.catalyst_debug_chrome_stop) + : mApplicationContext.getString(R.string.catalyst_debug_chrome) + : mDevSettings.isRemoteJSDebugEnabled() + ? mApplicationContext.getString(R.string.catalyst_debug_stop) + : mApplicationContext.getString(R.string.catalyst_debug), + new DevOptionHandler() { + @Override + public void onOptionSelected() { + mDevSettings.setRemoteJSDebugEnabled(!mDevSettings.isRemoteJSDebugEnabled()); + handleReloadJS(); + } + }); + if (mDevSettings.isNuclideJSDebugEnabled()) { + options.put( + mApplicationContext.getString(R.string.catalyst_debug_nuclide), new DevOptionHandler() { @Override public void onOptionSelected() { - if (!mDevSettings.isJSDevModeEnabled() && mDevSettings.isHotModuleReplacementEnabled()) { - Toast.makeText(mApplicationContext, "HMR cannot be enabled when Dev mode is off. Disabling HMR...", Toast.LENGTH_LONG).show(); - mDevSettings.setHotModuleReplacementEnabled(false); - } - handleReloadJS(); + mDevServerHelper.attachDebugger(mApplicationContext, "ReactNative"); } }); - if (mDevSettings.isNuclideJSDebugEnabled()) { - String nuclideJsDebugMenuItemTitle = - mApplicationContext.getString(R.string.catalyst_debugjs_nuclide); - options.put( - nuclideJsDebugMenuItemTitle, - new DevOptionHandler() { - @Override - public void onOptionSelected() { - mDevServerHelper.attachDebugger(mApplicationContext, "ReactNative"); - } - }); } - String remoteJsDebugMenuItemTitle = - mDevSettings.isRemoteJSDebugEnabled() - ? mApplicationContext.getString(R.string.catalyst_debugjs_off) - : mApplicationContext.getString(R.string.catalyst_debugjs); options.put( - remoteJsDebugMenuItemTitle, + // NOTE: `isElementInspectorEnabled` is not guaranteed to be accurate. + mApplicationContext.getString(R.string.catalyst_inspector), new DevOptionHandler() { @Override public void onOptionSelected() { - mDevSettings.setRemoteJSDebugEnabled(!mDevSettings.isRemoteJSDebugEnabled()); - handleReloadJS(); + mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled()); + mReactInstanceManagerHelper.toggleElementInspector(); } }); options.put( mDevSettings.isReloadOnJSChangeEnabled() - ? mApplicationContext.getString(R.string.catalyst_live_reload_off) - : mApplicationContext.getString(R.string.catalyst_live_reload), + ? mApplicationContext.getString(R.string.catalyst_reload_on_save_stop) + : mApplicationContext.getString(R.string.catalyst_reload_on_save), new DevOptionHandler() { @Override public void onOptionSelected() { @@ -469,32 +482,26 @@ public void onOptionSelected() { } }); options.put( - mDevSettings.isHotModuleReplacementEnabled() - ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off) - : mApplicationContext.getString(R.string.catalyst_hot_module_replacement), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - if (!mDevSettings.isHotModuleReplacementEnabled() && !mDevSettings.isJSDevModeEnabled()) { - Toast.makeText(mApplicationContext, "You're trying to enable HMR while Dev mode is off. Turning both HMR and the Dev mode on...", Toast.LENGTH_LONG).show(); - mDevSettings.setJSDevModeEnabled(true); - } - mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled()); - handleReloadJS(); - } - }); - options.put( - mApplicationContext.getString(R.string.catalyst_element_inspector), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled()); - mReactInstanceManagerHelper.toggleElementInspector(); - } - }); + mDevSettings.isHotModuleReplacementEnabled() + ? mApplicationContext.getString(R.string.catalyst_hot_reloading_stop) + : mApplicationContext.getString(R.string.catalyst_hot_reloading), + new DevOptionHandler() { + @Override + public void onOptionSelected() { + if (!mDevSettings.isHotModuleReplacementEnabled() && !mDevSettings.isJSDevModeEnabled()) { + Toast.makeText( + mApplicationContext, + mApplicationContext.getString(R.string.catalyst_hot_reloading_auto_enable), + Toast.LENGTH_LONG).show(); + mDevSettings.setJSDevModeEnabled(true); + } + mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled()); + handleReloadJS(); + } + }); options.put( mDevSettings.isFpsDebugEnabled() - ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off) + ? mApplicationContext.getString(R.string.catalyst_perf_monitor_stop) : mApplicationContext.getString(R.string.catalyst_perf_monitor), new DevOptionHandler() { @Override @@ -884,10 +891,10 @@ public void onSuccess() { public void onFailure(final Throwable cause) { mDevLoadingViewController.hide(); mDevLoadingViewVisible = false; - FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause); + FLog.e(ReactConstants.TAG, "Failed to connect to debugger!", cause); future.setException( new IOException( - mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause)); + mApplicationContext.getString(R.string.catalyst_debug_error), cause)); } }; } @@ -951,7 +958,7 @@ public void run() { showNewJavaError(debugServerException.getMessage(), cause); } else { showNewJavaError( - mApplicationContext.getString(R.string.catalyst_jsload_error), + mApplicationContext.getString(R.string.catalyst_reload_error), cause); } } diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml index 125f48d6195af7..4b04fddbbc7d48 100644 --- a/ReactAndroid/src/main/res/devsupport/values/strings.xml +++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml @@ -1,22 +1,26 @@ - Reload - Debug JS in Nuclide - The request to attach Nuclide could not reach Metro Bundler! - Debug JS Remotely - Stop Remote JS Debugging - Enable Hot Reloading - Disable Hot Reloading - Enable Live Reload - Disable Live Reload + Reload + Failed to load bundle. Try restarting the bundler or reconnecting your device. + Debug + Stop Debugging + Connecting to debugger... + Failed to connect to debugger! + Debug with Chrome + Stop Chrome Debugging + Debug with Nuclide + Failed to communicate with the bundler to enabling debugging with Nuclide. + Enable Reload-on-Save + Disable Reload-on-Save + Enable Hot Reloading + Disable Hot Reloading + Disabling hot reloading because it requires a development bundle. + Switching to development bundle in order to enable hot reloading. + Toggle Inspector Show Perf Monitor - Hide Perf Monitor - Dev Settings - Catalyst Dev Settings - Unable to download JS bundle. Did you forget to start the development server or connect your device? - Connecting to remote debugger - Unable to connect with remote debugger - Toggle Inspector + Hide Perf Monitor + Settings + Debug Settings Capture Heap Dismiss\n(ESC) Reload\n(R,\u00A0R) From db9fc388932370f39aee412dc1d181a217f60226 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 31 May 2019 00:41:48 -0700 Subject: [PATCH 040/330] Log `console.log` invocations to the Metro terminal. Summary: People ask "How do you use `console.log` with React Native?" and there is no good answer. This diff aims to stop people from asking this question. See https://fb.workplace.com/groups/rn.core/permalink/2372327062999018/ for context. This logging relies on network requests which can cause logs to show up out-of-order. To reduce the likelihood I queue every log message on the server for a maximum of 200ms. There could be other methods, like using websocket, but that seems more complex than is necessary at least in the beginning. I considered various throttling strategies because this could be quite chatty and possibly problematic, however I think we can just ship this and iterate based on feedback. On my very underpowered laptop I logged a random number every 10 milliseconds and it didn't cause any issues or slowdown. Reviewed By: gaearon Differential Revision: D15559151 fbshipit-source-id: 552001622af0937ae3a37d2bd8c1b96e7ca52020 --- Libraries/Core/Devtools/logToConsole.js | 33 +++++++++++++++++++++++++ Libraries/Core/setUpDeveloperTools.js | 10 ++++++++ 2 files changed, 43 insertions(+) create mode 100644 Libraries/Core/Devtools/logToConsole.js diff --git a/Libraries/Core/Devtools/logToConsole.js b/Libraries/Core/Devtools/logToConsole.js new file mode 100644 index 00000000000000..ecad232cb98a63 --- /dev/null +++ b/Libraries/Core/Devtools/logToConsole.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +const getDevServer = require('./getDevServer'); + +let ID = 0; + +function logToConsole( + level: 'trace' | 'info' | 'warn' | 'log', + data: Array, +) { + let body; + try { + body = JSON.stringify({id: ID++, level, data}); + } catch (error) { + body = JSON.stringify({id: ID++, level, data: [error.message]}); + } + fetch(getDevServer().url + 'log-to-console', { + method: 'POST', + body, + }); +} + +module.exports = logToConsole; diff --git a/Libraries/Core/setUpDeveloperTools.js b/Libraries/Core/setUpDeveloperTools.js index e18b5be9740199..da9aa45c50e457 100644 --- a/Libraries/Core/setUpDeveloperTools.js +++ b/Libraries/Core/setUpDeveloperTools.js @@ -25,4 +25,14 @@ if (__DEV__) { const JSInspector = require('../JSInspector/JSInspector'); JSInspector.registerAgent(require('../JSInspector/NetworkAgent')); } + + const logToConsole = require('./Devtools/logToConsole'); + ['log', 'warn', 'info', 'trace'].forEach(level => { + const originalFunction = console[level]; + // $FlowFixMe Overwrite console methods + console[level] = function(...args) { + logToConsole(level, args); + originalFunction.apply(console, args); + }; + }); } From 5b7edb59a5198f6c00ece5c97c3c6b917a56313b Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Fri, 31 May 2019 00:43:59 -0700 Subject: [PATCH 041/330] fix shouldComponentUpdate in YellowBox (#25097) Summary: The previous comparison does not make sense (accessing props by index) - and always returns true. I'm going to assume there was a reason for implementing `shouldComponentUpdate` - although personally I'd just go for PureComponent (even if it may not be 100% accurate). Let me know if PureComponent sounds better. ## Changelog not needed Pull Request resolved: https://github.com/facebook/react-native/pull/25097 Differential Revision: D15575079 Pulled By: cpojer fbshipit-source-id: 49aeb9d2997d3c613fe7a1af4534dff1607d53b4 --- Libraries/YellowBox/UI/YellowBoxListRow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/YellowBox/UI/YellowBoxListRow.js b/Libraries/YellowBox/UI/YellowBoxListRow.js index d10f11b9034709..f388c5083b117d 100644 --- a/Libraries/YellowBox/UI/YellowBoxListRow.js +++ b/Libraries/YellowBox/UI/YellowBoxListRow.js @@ -38,7 +38,7 @@ class YellowBoxListRow extends React.Component { prevProps.onPress !== nextProps.onPress || prevProps.warnings.length !== nextProps.warnings.length || prevProps.warnings.some( - (prevWarning, index) => prevWarning !== nextProps[index], + (prevWarning, index) => prevWarning !== nextProps.warnings[index], ) ); } From a1bfb284ee6fcd8832b7f2939fb2ea97117d5075 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 31 May 2019 01:21:25 -0700 Subject: [PATCH 042/330] Use atomic list for event subscribers Summary: Replace the *copy on write* vector with an atomic pointer to a linked list. This allows to publish without locking a mutex, at the cost of the slower traversal of a linked list (a vector has better locality). At the moment, the typical use case is to have one subscriber, meaning that the afforementioned slower traversal is not a problem. Adding subscribers is implemented as atomic *compare and swap.* Reviewed By: SidharthGuglani Differential Revision: D15546964 fbshipit-source-id: 41bfa41f1ac6be5c9b6bf4288ea3271ee995877e --- ReactCommon/yoga/yoga/event/event.cpp | 56 +++++++++++++++------------ 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/ReactCommon/yoga/yoga/event/event.cpp b/ReactCommon/yoga/yoga/event/event.cpp index e2fe3588f1f96d..02e70dce02eb33 100644 --- a/ReactCommon/yoga/yoga/event/event.cpp +++ b/ReactCommon/yoga/yoga/event/event.cpp @@ -5,51 +5,57 @@ * file in the root directory of this source tree. */ #include "event.h" +#include #include #include -#include - -#include namespace facebook { namespace yoga { namespace { -std::mutex& eventSubscribersMutex() { - static std::mutex subscribersMutex; - return subscribersMutex; -} +struct Node { + std::function subscriber = nullptr; + Node* next = nullptr; + + Node(std::function&& subscriber) + : subscriber{std::move(subscriber)} {} +}; -std::shared_ptr& eventSubscribers() { - static auto subscribers = std::make_shared(); - return subscribers; +std::atomic subscribers{nullptr}; + +Node* push(Node* newHead) { + Node* oldHead; + do { + oldHead = subscribers.load(std::memory_order_relaxed); + if (newHead != nullptr) { + newHead->next = oldHead; + } + } while (!subscribers.compare_exchange_weak( + oldHead, newHead, std::memory_order_release, std::memory_order_relaxed)); + return oldHead; } } // namespace void Event::reset() { - eventSubscribers() = std::make_shared(); + auto head = push(nullptr); + while (head != nullptr) { + auto current = head; + head = head->next; + delete current; + } } void Event::subscribe(std::function&& subscriber) { - std::lock_guard guard(eventSubscribersMutex()); - eventSubscribers() = - std::make_shared(*eventSubscribers()); - eventSubscribers()->push_back(subscriber); + push(new Node{std::move(subscriber)}); } void Event::publish(const YGNode& node, Type eventType, const Data& eventData) { - std::shared_ptr subscribers; - { - std::lock_guard guard(eventSubscribersMutex()); - subscribers = eventSubscribers(); - } - - for (auto& subscriber : *subscribers) { - if (subscriber) { - subscriber(node, eventType, eventData); - } + for (auto subscriber = subscribers.load(std::memory_order_relaxed); + subscriber != nullptr; + subscriber = subscriber->next) { + subscriber->subscriber(node, eventType, eventData); } } From bccc92dfdd2d85933f2a9cb5c8d1773affb7acba Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Fri, 31 May 2019 01:32:13 -0700 Subject: [PATCH 043/330] Remove vendored fetch polyfill, update to whatwg-fetch@3.0 (#24418) Summary: The original reason for vendoring the fetch polyfill was to remove the default blob response type but this was reverted. Here's a little history around the fetch polyfill and the blob issue: - Original commit introducing the vendored polyfill: #19333, the goal was to fix a memory leak because our blob implementation doesn't release resources automatically. Not an ideal fix but since the issue was pretty severe and the infra for a proper fix was not in place. - This introduced an issue when downloading images using `fetch` which was fixed by #22063 which re-added the default blob content type. However that re-introduced the original fetch memory leak. - We have better infra now with jsi and I was able to get blob deallocation working, see #24405 Currently the vendored fetch polyfill is useless since it was changed back to the original version. We can just use the npm version again. I also updated to 3.0 which brings better spec compliance and support for cancellation via `AbortController`, https://github.com/github/fetch/releases/tag/v3.0.0. ## Changelog [General] [Changed] - Remove vendored fetch polyfill, update to whatwg-fetch@3.0 Pull Request resolved: https://github.com/facebook/react-native/pull/24418 Differential Revision: D14932683 Pulled By: cpojer fbshipit-source-id: 915e3d25978e8b9d7507ed807e7fba45aa88385a --- Libraries/Core/setUpGlobals.js | 4 + Libraries/Network/fetch.js | 2 +- Libraries/vendor/core/whatwg-fetch.js | 533 -------------------------- package.json | 3 +- yarn.lock | 2 +- 5 files changed, 8 insertions(+), 536 deletions(-) delete mode 100644 Libraries/vendor/core/whatwg-fetch.js diff --git a/Libraries/Core/setUpGlobals.js b/Libraries/Core/setUpGlobals.js index 0310f3c2bcf047..b4cdf775eb6e54 100644 --- a/Libraries/Core/setUpGlobals.js +++ b/Libraries/Core/setUpGlobals.js @@ -21,6 +21,10 @@ if (global.window === undefined) { global.window = global; } +if (global.self === undefined) { + global.self = global; +} + // Set up process global.process = global.process || {}; global.process.env = global.process.env || {}; diff --git a/Libraries/Network/fetch.js b/Libraries/Network/fetch.js index ec9c28f1860a93..66687e70de2035 100644 --- a/Libraries/Network/fetch.js +++ b/Libraries/Network/fetch.js @@ -11,7 +11,7 @@ 'use strict'; -const whatwg = require('../vendor/core/whatwg-fetch'); +const whatwg = require('whatwg-fetch'); if (whatwg && whatwg.fetch) { module.exports = whatwg; diff --git a/Libraries/vendor/core/whatwg-fetch.js b/Libraries/vendor/core/whatwg-fetch.js deleted file mode 100644 index 3f1767afda813e..00000000000000 --- a/Libraries/vendor/core/whatwg-fetch.js +++ /dev/null @@ -1,533 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -// Fork of https://github.com/github/fetch/blob/master/fetch.js that does not -// use reponseType: 'blob' by default. RN already has specific native implementations -// for different response types so there is no need to add the extra blob overhead. - -// Copyright (c) 2014-2016 GitHub, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -(function(self) { - 'use strict'; - - if (self.fetch) { - return; - } - - var support = { - searchParams: 'URLSearchParams' in self, - iterable: 'Symbol' in self && 'iterator' in Symbol, - blob: - 'FileReader' in self && - 'Blob' in self && - (function() { - try { - new Blob(); - return true; - } catch (e) { - return false; - } - })(), - formData: 'FormData' in self, - arrayBuffer: 'ArrayBuffer' in self, - }; - - if (support.arrayBuffer) { - var viewClasses = [ - '[object Int8Array]', - '[object Uint8Array]', - '[object Uint8ClampedArray]', - '[object Int16Array]', - '[object Uint16Array]', - '[object Int32Array]', - '[object Uint32Array]', - '[object Float32Array]', - '[object Float64Array]', - ]; - - var isDataView = function(obj) { - return obj && DataView.prototype.isPrototypeOf(obj); - }; - - var isArrayBufferView = - ArrayBuffer.isView || - function(obj) { - return ( - obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1 - ); - }; - } - - function normalizeName(name) { - if (typeof name !== 'string') { - name = String(name); - } - if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { - throw new TypeError('Invalid character in header field name'); - } - return name.toLowerCase(); - } - - function normalizeValue(value) { - if (typeof value !== 'string') { - value = String(value); - } - return value; - } - - // Build a destructive iterator for the value list - function iteratorFor(items) { - var iterator = { - next: function() { - var value = items.shift(); - return {done: value === undefined, value: value}; - }, - }; - - if (support.iterable) { - iterator[Symbol.iterator] = function() { - return iterator; - }; - } - - return iterator; - } - - function Headers(headers) { - this.map = {}; - - if (headers instanceof Headers) { - headers.forEach(function(value, name) { - this.append(name, value); - }, this); - } else if (Array.isArray(headers)) { - headers.forEach(function(header) { - this.append(header[0], header[1]); - }, this); - } else if (headers) { - Object.getOwnPropertyNames(headers).forEach(function(name) { - this.append(name, headers[name]); - }, this); - } - } - - Headers.prototype.append = function(name, value) { - name = normalizeName(name); - value = normalizeValue(value); - var oldValue = this.map[name]; - this.map[name] = oldValue ? oldValue + ',' + value : value; - }; - - Headers.prototype['delete'] = function(name) { - delete this.map[normalizeName(name)]; - }; - - Headers.prototype.get = function(name) { - name = normalizeName(name); - return this.has(name) ? this.map[name] : null; - }; - - Headers.prototype.has = function(name) { - return this.map.hasOwnProperty(normalizeName(name)); - }; - - Headers.prototype.set = function(name, value) { - this.map[normalizeName(name)] = normalizeValue(value); - }; - - Headers.prototype.forEach = function(callback, thisArg) { - for (var name in this.map) { - if (this.map.hasOwnProperty(name)) { - callback.call(thisArg, this.map[name], name, this); - } - } - }; - - Headers.prototype.keys = function() { - var items = []; - this.forEach(function(value, name) { - items.push(name); - }); - return iteratorFor(items); - }; - - Headers.prototype.values = function() { - var items = []; - this.forEach(function(value) { - items.push(value); - }); - return iteratorFor(items); - }; - - Headers.prototype.entries = function() { - var items = []; - this.forEach(function(value, name) { - items.push([name, value]); - }); - return iteratorFor(items); - }; - - if (support.iterable) { - Headers.prototype[Symbol.iterator] = Headers.prototype.entries; - } - - function consumed(body) { - if (body.bodyUsed) { - return Promise.reject(new TypeError('Already read')); - } - body.bodyUsed = true; - } - - function fileReaderReady(reader) { - return new Promise(function(resolve, reject) { - reader.onload = function() { - resolve(reader.result); - }; - reader.onerror = function() { - reject(reader.error); - }; - }); - } - - function readBlobAsArrayBuffer(blob) { - var reader = new FileReader(); - var promise = fileReaderReady(reader); - reader.readAsArrayBuffer(blob); - return promise; - } - - function readBlobAsText(blob) { - var reader = new FileReader(); - var promise = fileReaderReady(reader); - reader.readAsText(blob); - return promise; - } - - function readArrayBufferAsText(buf) { - var view = new Uint8Array(buf); - var chars = new Array(view.length); - - for (var i = 0; i < view.length; i++) { - chars[i] = String.fromCharCode(view[i]); - } - return chars.join(''); - } - - function bufferClone(buf) { - if (buf.slice) { - return buf.slice(0); - } else { - var view = new Uint8Array(buf.byteLength); - view.set(new Uint8Array(buf)); - return view.buffer; - } - } - - function Body() { - this.bodyUsed = false; - - this._initBody = function(body) { - this._bodyInit = body; - if (!body) { - this._bodyText = ''; - } else if (typeof body === 'string') { - this._bodyText = body; - } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { - this._bodyBlob = body; - } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { - this._bodyFormData = body; - } else if ( - support.searchParams && - URLSearchParams.prototype.isPrototypeOf(body) - ) { - this._bodyText = body.toString(); - } else if (support.arrayBuffer && support.blob && isDataView(body)) { - this._bodyArrayBuffer = bufferClone(body.buffer); - // IE 10-11 can't handle a DataView body. - this._bodyInit = new Blob([this._bodyArrayBuffer]); - } else if ( - support.arrayBuffer && - (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body)) - ) { - this._bodyArrayBuffer = bufferClone(body); - } else { - throw new Error('unsupported BodyInit type'); - } - - if (!this.headers.get('content-type')) { - if (typeof body === 'string') { - this.headers.set('content-type', 'text/plain;charset=UTF-8'); - } else if (this._bodyBlob && this._bodyBlob.type) { - this.headers.set('content-type', this._bodyBlob.type); - } else if ( - support.searchParams && - URLSearchParams.prototype.isPrototypeOf(body) - ) { - this.headers.set( - 'content-type', - 'application/x-www-form-urlencoded;charset=UTF-8', - ); - } - } - }; - - if (support.blob) { - this.blob = function() { - var rejected = consumed(this); - if (rejected) { - return rejected; - } - - if (this._bodyBlob) { - return Promise.resolve(this._bodyBlob); - } else if (this._bodyArrayBuffer) { - return Promise.resolve(new Blob([this._bodyArrayBuffer])); - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as blob'); - } else { - return Promise.resolve(new Blob([this._bodyText])); - } - }; - - this.arrayBuffer = function() { - if (this._bodyArrayBuffer) { - return consumed(this) || Promise.resolve(this._bodyArrayBuffer); - } else { - return this.blob().then(readBlobAsArrayBuffer); - } - }; - } - - this.text = function() { - var rejected = consumed(this); - if (rejected) { - return rejected; - } - - if (this._bodyBlob) { - return readBlobAsText(this._bodyBlob); - } else if (this._bodyArrayBuffer) { - return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)); - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as text'); - } else { - return Promise.resolve(this._bodyText); - } - }; - - if (support.formData) { - this.formData = function() { - return this.text().then(decode); - }; - } - - this.json = function() { - return this.text().then(JSON.parse); - }; - - return this; - } - - // HTTP methods whose capitalization should be normalized - var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']; - - function normalizeMethod(method) { - var upcased = method.toUpperCase(); - return methods.indexOf(upcased) > -1 ? upcased : method; - } - - function Request(input, options) { - options = options || {}; - var body = options.body; - - if (input instanceof Request) { - if (input.bodyUsed) { - throw new TypeError('Already read'); - } - this.url = input.url; - this.credentials = input.credentials; - if (!options.headers) { - this.headers = new Headers(input.headers); - } - this.method = input.method; - this.mode = input.mode; - if (!body && input._bodyInit != null) { - body = input._bodyInit; - input.bodyUsed = true; - } - } else { - this.url = String(input); - } - - this.credentials = options.credentials || this.credentials || 'omit'; - if (options.headers || !this.headers) { - this.headers = new Headers(options.headers); - } - this.method = normalizeMethod(options.method || this.method || 'GET'); - this.mode = options.mode || this.mode || null; - this.referrer = null; - - if ((this.method === 'GET' || this.method === 'HEAD') && body) { - throw new TypeError('Body not allowed for GET or HEAD requests'); - } - this._initBody(body); - } - - Request.prototype.clone = function() { - return new Request(this, {body: this._bodyInit}); - }; - - function decode(body) { - var form = new FormData(); - body - .trim() - .split('&') - .forEach(function(bytes) { - if (bytes) { - var split = bytes.split('='); - var name = split.shift().replace(/\+/g, ' '); - var value = split.join('=').replace(/\+/g, ' '); - form.append(decodeURIComponent(name), decodeURIComponent(value)); - } - }); - return form; - } - - function parseHeaders(rawHeaders) { - var headers = new Headers(); - // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space - // https://tools.ietf.org/html/rfc7230#section-3.2 - var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' '); - preProcessedHeaders.split(/\r?\n/).forEach(function(line) { - var parts = line.split(':'); - var key = parts.shift().trim(); - if (key) { - var value = parts.join(':').trim(); - headers.append(key, value); - } - }); - return headers; - } - - Body.call(Request.prototype); - - function Response(bodyInit, options) { - if (!options) { - options = {}; - } - - this.type = 'default'; - this.status = options.status === undefined ? 200 : options.status; - this.ok = this.status >= 200 && this.status < 300; - this.statusText = 'statusText' in options ? options.statusText : 'OK'; - this.headers = new Headers(options.headers); - this.url = options.url || ''; - this._initBody(bodyInit); - } - - Body.call(Response.prototype); - - Response.prototype.clone = function() { - return new Response(this._bodyInit, { - status: this.status, - statusText: this.statusText, - headers: new Headers(this.headers), - url: this.url, - }); - }; - - Response.error = function() { - var response = new Response(null, {status: 0, statusText: ''}); - response.type = 'error'; - return response; - }; - - var redirectStatuses = [301, 302, 303, 307, 308]; - - Response.redirect = function(url, status) { - if (redirectStatuses.indexOf(status) === -1) { - throw new RangeError('Invalid status code'); - } - - return new Response(null, {status: status, headers: {location: url}}); - }; - - self.Headers = Headers; - self.Request = Request; - self.Response = Response; - - self.fetch = function(input, init) { - return new Promise(function(resolve, reject) { - var request = new Request(input, init); - var xhr = new XMLHttpRequest(); - - xhr.onload = function() { - var options = { - status: xhr.status, - statusText: xhr.statusText, - headers: parseHeaders(xhr.getAllResponseHeaders() || ''), - }; - options.url = - 'responseURL' in xhr - ? xhr.responseURL - : options.headers.get('X-Request-URL'); - var body = 'response' in xhr ? xhr.response : xhr.responseText; - resolve(new Response(body, options)); - }; - - xhr.onerror = function() { - reject(new TypeError('Network request failed')); - }; - - xhr.ontimeout = function() { - reject(new TypeError('Network request failed')); - }; - - xhr.open(request.method, request.url, true); - - if (request.credentials === 'include') { - xhr.withCredentials = true; - } else if (request.credentials === 'omit') { - xhr.withCredentials = false; - } - - if ('responseType' in xhr && support.blob) { - xhr.responseType = 'blob'; - } - - request.headers.forEach(function(value, name) { - xhr.setRequestHeader(name, value); - }); - - xhr.send( - typeof request._bodyInit === 'undefined' ? null : request._bodyInit, - ); - }); - }; - self.fetch.polyfill = true; -})(typeof self !== 'undefined' ? self : this); diff --git a/package.json b/package.json index fb864871321e10..47fbc2b66db8ca 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,8 @@ "prop-types": "^15.7.2", "react-devtools-core": "^3.6.0", "regenerator-runtime": "^0.13.2", - "stacktrace-parser": "^0.1.3" + "stacktrace-parser": "^0.1.3", + "whatwg-fetch": "^3.0.0" }, "devDependencies": { "@babel/core": "^7.0.0", diff --git a/yarn.lock b/yarn.lock index 702e94ae62fb01..0eda165a2609d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7356,7 +7356,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: dependencies: iconv-lite "0.4.24" -whatwg-fetch@>=0.10.0: +whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== From 90938d60535c256981c80dae79309b7fa2638e84 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 May 2019 02:14:57 -0700 Subject: [PATCH 044/330] Fixes text style lost when enable maxLength (#24989) Summary: To fix https://github.com/facebook/react-native/issues/24983, we lost text style when `maxLength` enabled. ## Changelog [iOS] [Fixed] - Fixes text style lost when enable maxLength Pull Request resolved: https://github.com/facebook/react-native/pull/24989 Differential Revision: D15575493 Pulled By: cpojer fbshipit-source-id: 60129d2c24f7985ea0da38354078dfeea28157bc --- Libraries/Text/TextInput/RCTBaseTextInputView.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index d9b0d7310d818f..5ffce4cd49e8ec 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -381,7 +381,12 @@ - (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSStrin // Truncate the input string so the result is exactly maxLength NSString *limitedString = [text substringToIndex:allowedLength]; NSMutableAttributedString *newAttributedText = [backedTextInputView.attributedText mutableCopy]; - [newAttributedText replaceCharactersInRange:range withString:limitedString]; + // Apply text attributes if original input view doesn't have text. + if (backedTextInputView.attributedText.length == 0) { + newAttributedText = [[NSMutableAttributedString alloc] initWithString:[self.textAttributes applyTextAttributesToText:limitedString] attributes:self.textAttributes.effectiveTextAttributes]; + } else { + [newAttributedText replaceCharactersInRange:range withString:limitedString]; + } backedTextInputView.attributedText = newAttributedText; _predictedText = newAttributedText.string; From 74f56bd55793d49d84b1068eb3ed9042aeb341e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Fri, 31 May 2019 02:26:37 -0700 Subject: [PATCH 045/330] Add method to get a segment path without injecting it in the VM Reviewed By: cpojer Differential Revision: D15575463 fbshipit-source-id: 0b481c48f02353e0d15e0dec6162850a0e2140e9 --- .../SegmentFetcher/NativeSegmentFetcher.js | 5 ++ Libraries/Core/setUpSegmentFetcher.js | 47 +++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js index 38319e03456d68..765b8ef0e07ef3 100644 --- a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js +++ b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js @@ -18,6 +18,11 @@ export interface Spec extends TurboModule { options: Object, // flowlint-line unclear-type: off callback: (error: ?Object) => void, // flowlint-line unclear-type: off ) => void; + +getSegment?: ( + segmentId: number, + options: Object, // flowlint-line unclear-type: off + callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off + ) => void; } export default TurboModuleRegistry.getEnforcing('SegmentFetcher'); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js index dd182a69c91bb7..3d811535ce38ee 100644 --- a/Libraries/Core/setUpSegmentFetcher.js +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -9,13 +9,20 @@ */ 'use strict'; +export type FetchSegmentFunction = typeof __fetchSegment; +export type GetSegmentFunction = typeof __getSegment; + /** * Set up SegmentFetcher. * You can use this module directly, or just require InitializeCore. */ -global.__fetchSegment = function( + +function __fetchSegment( segmentId: number, - options: {|+otaBuildNumber: ?string|}, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, callback: (?Error) => void, ) { const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') @@ -33,4 +40,38 @@ global.__fetchSegment = function( callback(null); }, ); -}; +} + +global.__fetchSegment = __fetchSegment; + +function __getSegment( + segmentId: number, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, + callback: (?Error, ?string) => void, +) { + const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') + .default; + + if (!SegmentFetcher.getSegment) { + throw new Error('SegmentFetcher.getSegment must be defined'); + } + + SegmentFetcher.getSegment( + segmentId, + options, + (errorObject: ?{message: string, code: string}, path: ?string) => { + if (errorObject) { + const error = new Error(errorObject.message); + (error: any).code = errorObject.code; // flowlint-line unclear-type: off + callback(error); + } + + callback(null, path); + }, + ); +} + +global.__getSegment = __getSegment; From 284c5f0ad023204458124167789f43321f12776d Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 May 2019 02:56:49 -0700 Subject: [PATCH 046/330] Using presentingViewController to dismiss Modal (#24959) Summary: Fixes https://github.com/facebook/react-native/issues/23463. Using `presentingViewController` to dismiss Modal VC directly, don't let Modal VC to find `presentingViewController`, then dismiss. ## Changelog [iOS] [Fixed] - Using presentingViewController to dismiss Modal Pull Request resolved: https://github.com/facebook/react-native/pull/24959 Differential Revision: D15575571 Pulled By: cpojer fbshipit-source-id: e275e7c7fef644c06cc8e64dba5b5a5af4129192 --- React/Views/RCTModalHostViewManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m index 6377683d2dc748..495b90d2dddd7e 100644 --- a/React/Views/RCTModalHostViewManager.m +++ b/React/Views/RCTModalHostViewManager.m @@ -89,7 +89,7 @@ - (void)dismissModalHostView:(RCTModalHostView *)modalHostView withViewControlle if (_dismissalBlock) { _dismissalBlock([modalHostView reactViewController], viewController, animated, completionBlock); } else { - [viewController dismissViewControllerAnimated:animated completion:completionBlock]; + [viewController.presentingViewController dismissViewControllerAnimated:animated completion:completionBlock]; } } From 9d0d7b61b69a0395ebbcb0ddbfb324e38dbe070a Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 May 2019 02:58:00 -0700 Subject: [PATCH 047/330] Add ultrabold pairs for font weight (#24948) Summary: Add `ultrabold` map of font weight, if not, `ultrabold` would map to `bold`. Fixes https://github.com/facebook/react-native/issues/23512. ## Changelog [iOS] [Fixed] - Add ultrabold pairs for font weight Pull Request resolved: https://github.com/facebook/react-native/pull/24948 Differential Revision: D15575568 Pulled By: cpojer fbshipit-source-id: 5d1d6a033c166d91a330526ba8996ac0416f3887 --- React/Views/RCTFont.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/React/Views/RCTFont.mm b/React/Views/RCTFont.mm index e686637953a751..8c0e6d88c81d0b 100644 --- a/React/Views/RCTFont.mm +++ b/React/Views/RCTFont.mm @@ -32,6 +32,7 @@ static RCTFontWeight weightOfFont(UIFont *font) @"semibold", @"demibold", @"extrabold", + @"ultrabold", @"bold", @"heavy", @"black" @@ -46,6 +47,7 @@ static RCTFontWeight weightOfFont(UIFont *font) @(UIFontWeightSemibold), @(UIFontWeightSemibold), @(UIFontWeightHeavy), + @(UIFontWeightHeavy), @(UIFontWeightBold), @(UIFontWeightHeavy), @(UIFontWeightBlack) From 1ed352517ad387b4b7e48ce2b0ba3b9f7a8508e8 Mon Sep 17 00:00:00 2001 From: James Ide Date: Fri, 31 May 2019 03:12:46 -0700 Subject: [PATCH 048/330] Explicitly separate mocked native modules from mocked JS modules (#24809) Summary: This commit more clearly defines the mocks RN sets up and uses paths instead of Haste names to define the mocks. The Jest setup script defined mocks for native modules (Obj-C, Java) and mocks for JS modules in the same data structure. This meant that some non-native modules (that is, JS modules) were in the `mockNativeModules` map -- this commit splits them out and mocks them in typical `jest.mock` fashion. Additionally, the setup script used to mock the modules using the Haste names. As one of the steps toward migrating to standard path-based imports, the setup script now mocks JS modules using paths (native modules don't need a Haste name nor path since they are just entries in `NativeModules`). This gets us closer to being able to remove `hasteImpl`. (Tracking in https://github.com/facebook/react-native/issues/24772.) Also, this commit removes mocks that are not referenced anywhere in the RN and React repositories (grepped for the names and found no entries outside of the Jest setup scripts). ## Changelog [General] [Changed] - Explicitly separate mocked native modules from mocked JS modules Pull Request resolved: https://github.com/facebook/react-native/pull/24809 Differential Revision: D15316882 Pulled By: cpojer fbshipit-source-id: 039e4e320121bea9580196fe0a091b8b1e8b41bf --- .../__tests__/resolveAssetSource-test.js | 29 +- jest/setup.js | 480 ++++++++---------- 2 files changed, 233 insertions(+), 276 deletions(-) diff --git a/Libraries/Image/__tests__/resolveAssetSource-test.js b/Libraries/Image/__tests__/resolveAssetSource-test.js index 195a5be549eda2..287e0657beb5ac 100644 --- a/Libraries/Image/__tests__/resolveAssetSource-test.js +++ b/Libraries/Image/__tests__/resolveAssetSource-test.js @@ -10,20 +10,20 @@ 'use strict'; -const AssetRegistry = require('../AssetRegistry'); -const Platform = require('../../Utilities/Platform'); -const resolveAssetSource = require('../resolveAssetSource'); - -import NativeSourceCode from '../../NativeModules/specs/NativeSourceCode'; - -function expectResolvesAsset(input, expectedSource) { - const assetId = AssetRegistry.registerAsset(input); - expect(resolveAssetSource(assetId)).toEqual(expectedSource); -} - describe('resolveAssetSource', () => { + let AssetRegistry; + let resolveAssetSource; + let NativeSourceCode; + let Platform; + beforeEach(() => { jest.resetModules(); + + AssetRegistry = require('../AssetRegistry'); + resolveAssetSource = require('../resolveAssetSource'); + NativeSourceCode = require('../../NativeModules/specs/NativeSourceCode') + .default; + Platform = require('../../Utilities/Platform'); }); it('returns same source for simple static and network images', () => { @@ -303,9 +303,16 @@ describe('resolveAssetSource', () => { ); }); }); + + function expectResolvesAsset(input, expectedSource) { + const assetId = AssetRegistry.registerAsset(input); + expect(resolveAssetSource(assetId)).toEqual(expectedSource); + } }); describe('resolveAssetSource.pickScale', () => { + const resolveAssetSource = require('../resolveAssetSource'); + it('picks matching scale', () => { expect(resolveAssetSource.pickScale([1], 2)).toBe(1); expect(resolveAssetSource.pickScale([1, 2, 3], 2)).toBe(2); diff --git a/jest/setup.js b/jest/setup.js index 38cef7befbf12f..d85849066c2d82 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -37,6 +37,53 @@ jest.setMock( jest .mock('../Libraries/Core/InitializeCore', () => {}) + .mock('../Libraries/ReactNative/UIManager', () => ({ + AndroidViewPager: { + Commands: { + setPage: jest.fn(), + setPageWithoutAnimation: jest.fn(), + }, + }, + blur: jest.fn(), + createView: jest.fn(), + customBubblingEventTypes: {}, + customDirectEventTypes: {}, + dispatchViewManagerCommand: jest.fn(), + focus: jest.fn(), + getViewManagerConfig: jest.fn(name => { + if (name === 'AndroidDrawerLayout') { + return { + Constants: { + DrawerPosition: { + Left: 10, + }, + }, + }; + } + }), + measure: jest.fn(), + manageChildren: jest.fn(), + removeSubviewsFromContainerWithID: jest.fn(), + replaceExistingNonRootView: jest.fn(), + setChildren: jest.fn(), + updateView: jest.fn(), + AndroidDrawerLayout: { + Constants: { + DrawerPosition: { + Left: 10, + }, + }, + }, + AndroidTextInput: { + Commands: {}, + }, + ScrollView: { + Constants: {}, + }, + View: { + Constants: {}, + }, + })) .mock('../Libraries/Image/Image', () => mockComponent('../Libraries/Image/Image'), ) @@ -52,6 +99,19 @@ jest .mock('../Libraries/Components/View/View', () => mockComponent('../Libraries/Components/View/View', MockNativeMethods), ) + .mock('../Libraries/Components/AccessibilityInfo/AccessibilityInfo', () => ({ + addEventListener: jest.fn(), + announceForAccessibility: jest.fn(), + fetch: jest.fn(), + isBoldTextEnabled: jest.fn(), + isGrayscaleEnabled: jest.fn(), + isInvertColorsEnabled: jest.fn(), + isReduceMotionEnabled: jest.fn(), + isReduceTransparencyEnabled: jest.fn(), + isScreenReaderEnabled: jest.fn(), + removeEventListener: jest.fn(), + setAccessibilityFocus: jest.fn(), + })) .mock('../Libraries/Components/RefreshControl/RefreshControl', () => jest.requireActual( '../Libraries/Components/RefreshControl/__mocks__/RefreshControlMock', @@ -82,6 +142,19 @@ jest }; return AnimatedImplementation; }) + .mock('../Libraries/AppState/AppState', () => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + })) + .mock('../Libraries/Linking/Linking', () => ({ + openURL: jest.fn(), + canOpenURL: jest.fn(() => Promise.resolve(true)), + openSettings: jest.fn(), + addEventListener: jest.fn(), + getInitialURL: jest.fn(() => Promise.resolve()), + removeEventListener: jest.fn(), + sendIntent: jest.fn(), + })) .mock('../Libraries/Renderer/shims/ReactNative', () => { const ReactNative = jest.requireActual( '../Libraries/Renderer/shims/ReactNative', @@ -97,283 +170,160 @@ jest }) .mock('../Libraries/Components/Touchable/ensureComponentIsNative', () => () => true, - ); - -const mockNativeModules = { - AccessibilityInfo: { - addEventListener: jest.fn(), - announceForAccessibility: jest.fn(), - fetch: jest.fn(), - isBoldTextEnabled: jest.fn(), - isGrayscaleEnabled: jest.fn(), - isInvertColorsEnabled: jest.fn(), - isReduceMotionEnabled: jest.fn(), - isReduceTransparencyEnabled: jest.fn(), - isScreenReaderEnabled: jest.fn(), - removeEventListener: jest.fn(), - setAccessibilityFocus: jest.fn(), - }, - AlertManager: { - alertWithArgs: jest.fn(), - }, - AppState: { - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - }, - AsyncLocalStorage: { - multiGet: jest.fn((keys, callback) => - process.nextTick(() => callback(null, [])), - ), - multiSet: jest.fn((entries, callback) => - process.nextTick(() => callback(null)), - ), - multiRemove: jest.fn((keys, callback) => - process.nextTick(() => callback(null)), - ), - multiMerge: jest.fn((entries, callback) => - process.nextTick(() => callback(null)), - ), - clear: jest.fn(callback => process.nextTick(() => callback(null))), - getAllKeys: jest.fn(callback => process.nextTick(() => callback(null, []))), - }, - BuildInfo: { - appVersion: '0', - buildVersion: '0', - getConstants() { - return { - appVersion: '0', - buildVersion: '0', - }; + ) + // Mock modules defined by the native layer (ex: Objective-C, Java) + .mock('../Libraries/BatchedBridge/NativeModules', () => ({ + AlertManager: { + alertWithArgs: jest.fn(), }, - }, - Clipboard: { - setString: jest.fn(), - }, - DataManager: { - queryData: jest.fn(), - }, - DeviceInfo: { - getConstants() { - return { - Dimensions: { - window: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, - }, - screen: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, + AsyncLocalStorage: { + multiGet: jest.fn((keys, callback) => + process.nextTick(() => callback(null, [])), + ), + multiSet: jest.fn((entries, callback) => + process.nextTick(() => callback(null)), + ), + multiRemove: jest.fn((keys, callback) => + process.nextTick(() => callback(null)), + ), + multiMerge: jest.fn((entries, callback) => + process.nextTick(() => callback(null)), + ), + clear: jest.fn(callback => process.nextTick(() => callback(null))), + getAllKeys: jest.fn(callback => + process.nextTick(() => callback(null, [])), + ), + }, + Clipboard: { + getString: jest.fn(() => ''), + setString: jest.fn(), + }, + DeviceInfo: { + getConstants() { + return { + Dimensions: { + window: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, + screen: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, }, - }, - }; + }; + }, }, - }, - FacebookSDK: { - login: jest.fn(), - logout: jest.fn(), - queryGraphPath: jest.fn((path, method, params, callback) => callback()), - }, - GraphPhotoUpload: { - upload: jest.fn(), - }, - I18n: { - translationsDictionary: JSON.stringify({ - 'Good bye, {name}!|Bye message': '\u{00A1}Adi\u{00F3}s {name}!', - }), - }, - ImageLoader: { - getSize: jest.fn(url => Promise.resolve({width: 320, height: 240})), - prefetchImage: jest.fn(), - }, - ImageViewManager: { - getSize: jest.fn((uri, success) => - process.nextTick(() => success(320, 240)), - ), - prefetchImage: jest.fn(), - }, - KeyboardObserver: { - addListener: jest.fn(), - removeListeners: jest.fn(), - }, - Linking: { - openURL: jest.fn(), - canOpenURL: jest.fn(() => Promise.resolve(true)), - openSettings: jest.fn(), - addEventListener: jest.fn(), - getInitialURL: jest.fn(() => Promise.resolve()), - removeEventListener: jest.fn(), - sendIntent: jest.fn(), - }, - LocationObserver: { - addListener: jest.fn(), - getCurrentPosition: jest.fn(), - removeListeners: jest.fn(), - requestAuthorization: jest.fn(), - setConfiguration: jest.fn(), - startObserving: jest.fn(), - stopObserving: jest.fn(), - }, - ModalFullscreenViewManager: {}, - NetInfo: { - fetch: jest.fn(() => Promise.resolve()), - getConnectionInfo: jest.fn(() => Promise.resolve()), - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - isConnected: { - fetch: jest.fn(() => Promise.resolve()), - addEventListener: jest.fn(), - removeEventListener: jest.fn(), + ImageLoader: { + getSize: jest.fn(url => Promise.resolve({width: 320, height: 240})), + prefetchImage: jest.fn(), }, - isConnectionExpensive: jest.fn(() => Promise.resolve()), - }, - Networking: { - sendRequest: jest.fn(), - abortRequest: jest.fn(), - addListener: jest.fn(), - removeListeners: jest.fn(), - }, - PlatformConstants: { - getConstants() { - return {}; + ImageViewManager: { + getSize: jest.fn((uri, success) => + process.nextTick(() => success(320, 240)), + ), + prefetchImage: jest.fn(), }, - }, - PushNotificationManager: { - presentLocalNotification: jest.fn(), - scheduleLocalNotification: jest.fn(), - cancelAllLocalNotifications: jest.fn(), - removeAllDeliveredNotifications: jest.fn(), - getDeliveredNotifications: jest.fn(callback => process.nextTick(() => [])), - removeDeliveredNotifications: jest.fn(), - setApplicationIconBadgeNumber: jest.fn(), - getApplicationIconBadgeNumber: jest.fn(callback => - process.nextTick(() => callback(0)), - ), - cancelLocalNotifications: jest.fn(), - getScheduledLocalNotifications: jest.fn(callback => - process.nextTick(() => callback()), - ), - requestPermissions: jest.fn(() => - Promise.resolve({alert: true, badge: true, sound: true}), - ), - abandonPermissions: jest.fn(), - checkPermissions: jest.fn(callback => - process.nextTick(() => callback({alert: true, badge: true, sound: true})), - ), - getInitialNotification: jest.fn(() => Promise.resolve(null)), - addListener: jest.fn(), - removeListeners: jest.fn(), - }, - SourceCode: { - getConstants() { - return { - scriptURL: null, - }; + KeyboardObserver: { + addListener: jest.fn(), + removeListeners: jest.fn(), }, - }, - StatusBarManager: { - HEIGHT: 42, - setColor: jest.fn(), - setStyle: jest.fn(), - setHidden: jest.fn(), - setNetworkActivityIndicatorVisible: jest.fn(), - setBackgroundColor: jest.fn(), - setTranslucent: jest.fn(), - }, - Timing: { - createTimer: jest.fn(), - deleteTimer: jest.fn(), - }, - UIManager: { - AndroidViewPager: { - Commands: { - setPage: jest.fn(), - setPageWithoutAnimation: jest.fn(), + Networking: { + sendRequest: jest.fn(), + abortRequest: jest.fn(), + addListener: jest.fn(), + removeListeners: jest.fn(), + }, + PlatformConstants: { + getConstants() { + return {}; }, }, - blur: jest.fn(), - createView: jest.fn(), - dispatchViewManagerCommand: jest.fn(), - focus: jest.fn(), - getViewManagerConfig: jest.fn(name => { - if (name === 'AndroidDrawerLayout') { + PushNotificationManager: { + presentLocalNotification: jest.fn(), + scheduleLocalNotification: jest.fn(), + cancelAllLocalNotifications: jest.fn(), + removeAllDeliveredNotifications: jest.fn(), + getDeliveredNotifications: jest.fn(callback => + process.nextTick(() => []), + ), + removeDeliveredNotifications: jest.fn(), + setApplicationIconBadgeNumber: jest.fn(), + getApplicationIconBadgeNumber: jest.fn(callback => + process.nextTick(() => callback(0)), + ), + cancelLocalNotifications: jest.fn(), + getScheduledLocalNotifications: jest.fn(callback => + process.nextTick(() => callback()), + ), + requestPermissions: jest.fn(() => + Promise.resolve({alert: true, badge: true, sound: true}), + ), + abandonPermissions: jest.fn(), + checkPermissions: jest.fn(callback => + process.nextTick(() => + callback({alert: true, badge: true, sound: true}), + ), + ), + getInitialNotification: jest.fn(() => Promise.resolve(null)), + addListener: jest.fn(), + removeListeners: jest.fn(), + }, + SourceCode: { + getConstants() { return { - Constants: { - DrawerPosition: { - Left: 10, - }, - }, + scriptURL: null, }; - } - }), - setChildren: jest.fn(), - manageChildren: jest.fn(), - updateView: jest.fn(), - removeSubviewsFromContainerWithID: jest.fn(), - replaceExistingNonRootView: jest.fn(), - customBubblingEventTypes: {}, - customDirectEventTypes: {}, - AndroidTextInput: { - Commands: {}, + }, }, - ModalFullscreenView: { - Constants: {}, + StatusBarManager: { + HEIGHT: 42, + setColor: jest.fn(), + setStyle: jest.fn(), + setHidden: jest.fn(), + setNetworkActivityIndicatorVisible: jest.fn(), + setBackgroundColor: jest.fn(), + setTranslucent: jest.fn(), }, - ScrollView: { - Constants: {}, + Timing: { + createTimer: jest.fn(), + deleteTimer: jest.fn(), }, - View: { - Constants: {}, + UIManager: {}, + BlobModule: { + getConstants: () => ({BLOB_URI_SCHEME: 'content', BLOB_URI_HOST: null}), + addNetworkingHandler: jest.fn(), + enableBlobSupport: jest.fn(), + disableBlobSupport: jest.fn(), + createFromParts: jest.fn(), + sendBlob: jest.fn(), + release: jest.fn(), }, - }, - BlobModule: { - getConstants: () => ({BLOB_URI_SCHEME: 'content', BLOB_URI_HOST: null}), - addNetworkingHandler: jest.fn(), - enableBlobSupport: jest.fn(), - disableBlobSupport: jest.fn(), - createFromParts: jest.fn(), - sendBlob: jest.fn(), - release: jest.fn(), - }, - WebSocketModule: { - connect: jest.fn(), - send: jest.fn(), - sendBinary: jest.fn(), - ping: jest.fn(), - close: jest.fn(), - addListener: jest.fn(), - removeListeners: jest.fn(), - }, -}; - -Object.keys(mockNativeModules).forEach(module => { - try { - jest.doMock(module, () => mockNativeModules[module]); // needed by FacebookSDK-test - } catch (e) { - jest.doMock(module, () => mockNativeModules[module], {virtual: true}); - } -}); - -jest.doMock( - '../Libraries/BatchedBridge/NativeModules', - () => mockNativeModules, -); - -jest.doMock('../Libraries/ReactNative/requireNativeComponent', () => { - const React = require('react'); - - return viewName => - class extends React.Component { - render() { - return React.createElement(viewName, this.props, this.props.children); - } - }; -}); + WebSocketModule: { + connect: jest.fn(), + send: jest.fn(), + sendBinary: jest.fn(), + ping: jest.fn(), + close: jest.fn(), + addListener: jest.fn(), + removeListeners: jest.fn(), + }, + })) + .mock('../Libraries/ReactNative/requireNativeComponent', () => { + const React = require('react'); -jest.doMock( - '../Libraries/Utilities/verifyComponentAttributeEquivalence', - () => function() {}, -); + return viewName => + class extends React.Component { + render() { + return React.createElement(viewName, this.props, this.props.children); + } + }; + }) + .mock( + '../Libraries/Utilities/verifyComponentAttributeEquivalence', + () => function() {}, + ); From a4f7e17a4f06ee713fecbfa1fbb1e632a9d3bf89 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Fri, 31 May 2019 03:51:56 -0700 Subject: [PATCH 049/330] Release underlying resources when JS instance is GC'ed on Android (#24767) Summary: Android followup for #24745. This adds a jsi object that removes blobs when it is gc'ed. We don't have many modules with native code on Android so I've added the native code directly in the blob package as a separate .so. I used a similar structure as the turbomodule package. ## Changelog [Android] [Fixed] - [Blob] Release underlying resources when JS instance is GC'ed on Android Pull Request resolved: https://github.com/facebook/react-native/pull/24767 Differential Revision: D15279651 Pulled By: cpojer fbshipit-source-id: 2bbdc4bbcbeae8945588ac5e3e895c49e6ac9e1a --- RNTester/android/app/BUCK | 1 + ReactAndroid/build.gradle | 1 + .../java/com/facebook/react/modules/blob/BUCK | 2 + .../react/modules/blob/BlobCollector.java | 25 ++++++++ .../react/modules/blob/BlobModule.java | 39 +++++++----- .../react/modules/blob/jni/Android.mk | 21 +++++++ .../com/facebook/react/modules/blob/jni/BUCK | 22 +++++++ .../react/modules/blob/jni/BlobCollector.cpp | 61 +++++++++++++++++++ .../react/modules/blob/jni/BlobCollector.h | 39 ++++++++++++ .../react/modules/blob/jni/OnLoad.cpp | 13 ++++ .../src/main/jni/react/jni/Android.mk | 2 + 11 files changed, 211 insertions(+), 15 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp diff --git a/RNTester/android/app/BUCK b/RNTester/android/app/BUCK index ceb05c3e109291..5e839d5e9153ca 100644 --- a/RNTester/android/app/BUCK +++ b/RNTester/android/app/BUCK @@ -25,6 +25,7 @@ rn_android_library( react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/common:build_config"), react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/views/text:text"), react_native_target("java/com/facebook/react/shell:shell"), react_native_target("jni/prebuilt:android-jsc"), # .so files are prebuilt by Gradle with `./gradlew :ReactAndroid:packageReactNdkLibsForBuck` diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 6e44769892cbbc..84207fb50578dc 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -222,6 +222,7 @@ def getNdkBuildFullPath() { task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog], type: Exec) { inputs.dir("$projectDir/../ReactCommon") inputs.dir("src/main/jni") + inputs.dir("src/main/java/com/facebook/react/modules/blob") outputs.dir("$buildDir/react-ndk/all") commandLine(getNdkBuildFullPath(), "NDK_PROJECT_PATH=null", diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index ac8fbcbc9f87ec..72c927348f08e4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -16,6 +16,7 @@ rn_android_library( ], deps = [ react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), + react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/java/okhttp:okhttp3"), @@ -24,6 +25,7 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/modules/blob/jni:jni"), react_native_target("java/com/facebook/react/modules/network:network"), react_native_target("java/com/facebook/react/modules/websocket:websocket"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java new file mode 100644 index 00000000000000..715f3dd38f6300 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java @@ -0,0 +1,25 @@ +package com.facebook.react.modules.blob; + +import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.ReactContext; +import com.facebook.soloader.SoLoader; + +/* package */ class BlobCollector { + static { + SoLoader.loadLibrary("reactnativeblob"); + } + + static void install(final ReactContext reactContext, final BlobModule blobModule) { + reactContext.runOnJSQueueThread(new Runnable() { + @Override + public void run() { + JavaScriptContextHolder jsContext = reactContext.getJavaScriptContextHolder(); + synchronized (jsContext) { + nativeInstall(blobModule, jsContext.get()); + } + } + }); + } + + private native static void nativeInstall(Object blobModule, long jsContext); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 830180c6ffc308..7bb5f281e49118 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -6,13 +6,10 @@ */ package com.facebook.react.modules.blob; -import android.content.ContentResolver; -import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; -import androidx.annotation.Nullable; import android.webkit.MimeTypeMap; import com.facebook.react.bridge.Arguments; @@ -40,6 +37,7 @@ import java.util.Map; import java.util.UUID; +import androidx.annotation.Nullable; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.ResponseBody; @@ -151,6 +149,11 @@ public BlobModule(ReactApplicationContext reactContext) { super(reactContext); } + @Override + public void initialize() { + BlobCollector.install(getReactApplicationContext(), this); + } + @Override public String getName() { return NAME; @@ -178,11 +181,15 @@ public String store(byte[] data) { } public void store(byte[] data, String blobId) { - mBlobs.put(blobId, data); + synchronized (mBlobs) { + mBlobs.put(blobId, data); + } } public void remove(String blobId) { - mBlobs.remove(blobId); + synchronized (mBlobs) { + mBlobs.remove(blobId); + } } public @Nullable byte[] resolve(Uri uri) { @@ -201,17 +208,19 @@ public void remove(String blobId) { } public @Nullable byte[] resolve(String blobId, int offset, int size) { - byte[] data = mBlobs.get(blobId); - if (data == null) { - return null; - } - if (size == -1) { - size = data.length - offset; - } - if (offset > 0 || size != data.length) { - data = Arrays.copyOfRange(data, offset, offset + size); + synchronized (mBlobs) { + byte[] data = mBlobs.get(blobId); + if (data == null) { + return null; + } + if (size == -1) { + size = data.length - offset; + } + if (offset > 0 || size != data.length) { + data = Arrays.copyOfRange(data, offset, offset + size); + } + return data; } - return data; } public @Nullable byte[] resolve(ReadableMap blob) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk new file mode 100644 index 00000000000000..b0ef370c574413 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk @@ -0,0 +1,21 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := reactnativeblob + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH) + +LOCAL_CFLAGS += -fvisibility=hidden -fexceptions -frtti + +LOCAL_STATIC_LIBRARIES := libjsi libjsireact jscruntime +LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni + +include $(BUILD_SHARED_LIBRARY) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK new file mode 100644 index 00000000000000..c02646779b63f8 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK @@ -0,0 +1,22 @@ +load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library") + +rn_xplat_cxx_library( + name = "jni", + srcs = glob(["*.cpp"]), + headers = glob(["*.h"]), + header_namespace = "", + compiler_flags = ["-fexceptions"], + fbandroid_allow_jni_merging = True, + platforms = ANDROID, + soname = "libreactnativeblob.$(ext)", + visibility = [ + "PUBLIC", + ], + deps = [ + "fbsource//xplat/folly:molly", + FBJNI_TARGET, + react_native_target("jni/react/jni:jni"), + react_native_xplat_target("jsi:JSCRuntime"), + react_native_xplat_target("jsiexecutor:jsiexecutor"), + ], +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp new file mode 100644 index 00000000000000..d14d3885253b9d --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp @@ -0,0 +1,61 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "BlobCollector.h" + +#include +#include +#include + +using namespace facebook; + +namespace facebook { +namespace react { + +static constexpr auto kBlobModuleJavaDescriptor = + "com/facebook/react/modules/blob/BlobModule"; + +BlobCollector::BlobCollector( + jni::global_ref blobModule, + const std::string &blobId) + : blobModule_(blobModule), blobId_(blobId) {} + +BlobCollector::~BlobCollector() { + auto removeMethod = jni::findClassStatic(kBlobModuleJavaDescriptor) + ->getMethod("remove"); + removeMethod(blobModule_, jni::make_jstring(blobId_).get()); +} + +void BlobCollector::nativeInstall( + jni::alias_ref jThis, + jni::alias_ref blobModule, + jlong jsContextNativePointer) { + auto &runtime = *((jsi::Runtime *)jsContextNativePointer); + auto blobModuleRef = jni::make_global(blobModule); + runtime.global().setProperty( + runtime, + "__blobCollectorProvider", + jsi::Function::createFromHostFunction( + runtime, + jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"), + 1, + [blobModuleRef]( + jsi::Runtime &rt, + const jsi::Value &thisVal, + const jsi::Value *args, + size_t count) { + auto blobId = args[0].asString(rt).utf8(rt); + auto blobCollector = + std::make_shared(blobModuleRef, blobId); + return jsi::Object::createFromHostObject(rt, blobCollector); + })); +} + +void BlobCollector::registerNatives() { + registerHybrid( + {makeNativeMethod("nativeInstall", BlobCollector::nativeInstall)}); +} + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h new file mode 100644 index 00000000000000..b013cf8bf665c7 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h @@ -0,0 +1,39 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class BlobCollector : public jni::HybridClass, + public jsi::HostObject { + public: + BlobCollector( + jni::global_ref blobManager, + const std::string &blobId); + ~BlobCollector(); + + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/modules/blob/BlobCollector;"; + + static void nativeInstall( + jni::alias_ref jThis, + jni::alias_ref blobModule, + jlong jsContextNativePointer); + + static void registerNatives(); + + private: + friend HybridBase; + + jni::global_ref blobModule_; + const std::string blobId_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp new file mode 100644 index 00000000000000..3707d02665e44a --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp @@ -0,0 +1,13 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include + +#include "BlobCollector.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + return facebook::jni::initialize( + vm, [] { facebook::react::BlobCollector::registerNatives(); }); +} diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 7d410f44c1078b..1cf03a78a5ea19 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -68,3 +68,5 @@ include $(REACT_SRC_DIR)/turbomodule/core/jni/Android.mk # $(call import-module,jscexecutor) include $(REACT_SRC_DIR)/jscexecutor/Android.mk + +include $(REACT_SRC_DIR)/modules/blob/jni/Android.mk From f6e1c164c2021fdaa8a8b0659dd341343594bd61 Mon Sep 17 00:00:00 2001 From: Petr Nikolaev Date: Fri, 31 May 2019 06:32:39 -0700 Subject: [PATCH 050/330] Revert D15572716: [RN] TM Spec: relax PermissionsAndroid enforcement Differential Revision: D15572716 Original commit changeset: 4a2edea608ab fbshipit-source-id: cb5ce87685dca9362d0c3df6f874d1a5470b05ac --- .../NativePermissionsAndroid.js | 2 +- .../PermissionsAndroid/PermissionsAndroid.js | 24 +------------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index 4212164d8baf83..025f9af18419b1 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -56,4 +56,4 @@ export interface Spec extends TurboModule { ) => Promise<{[permission: PermissionType]: PermissionStatus}>; } -export default TurboModuleRegistry.get('PermissionsAndroid'); +export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 427fb21c8a1f88..1b414e71165a29 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -11,11 +11,10 @@ 'use strict'; import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; +const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); import NativePermissionsAndroid from './NativePermissionsAndroid'; -import invariant from 'invariant'; - import type { PermissionStatus, PermissionType, @@ -91,11 +90,6 @@ class PermissionsAndroid { return Promise.resolve(false); } - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - return NativePermissionsAndroid.checkPermission(permission); } @@ -112,12 +106,6 @@ class PermissionsAndroid { ); return Promise.resolve(false); } - - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - return NativePermissionsAndroid.checkPermission(permission); } @@ -170,11 +158,6 @@ class PermissionsAndroid { return Promise.resolve(this.RESULTS.DENIED); } - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - if (rationale) { const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, @@ -214,11 +197,6 @@ class PermissionsAndroid { return Promise.resolve({}); } - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From a944ebd7da505cab8e5e1059d1844415e36ba434 Mon Sep 17 00:00:00 2001 From: Petr Nikolaev Date: Fri, 31 May 2019 06:32:39 -0700 Subject: [PATCH 051/330] Revert D15558093: [react-native][PR] [TM] Add spec for DevSettings Differential Revision: D15558093 Original commit changeset: 3adcb640a6ad fbshipit-source-id: 70b4842f5cdef878b18786c6a13e76694ffb1581 --- .../NativeModules/specs/NativeDevSettings.js | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 Libraries/NativeModules/specs/NativeDevSettings.js diff --git a/Libraries/NativeModules/specs/NativeDevSettings.js b/Libraries/NativeModules/specs/NativeDevSettings.js deleted file mode 100644 index 9a53a0db7905e0..00000000000000 --- a/Libraries/NativeModules/specs/NativeDevSettings.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -'use strict'; - -import type {TurboModule} from '../../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - +reload: () => void; - +setHotLoadingEnabled: (isHotLoadingEnabled: boolean) => void; - +setIsDebuggingRemotely: (isDebuggingRemotelyEnabled: boolean) => void; - +setLiveReloadEnabled: (isLiveReloadEnabled: boolean) => void; - +setProfilingEnabled: (isProfilingEnabled: boolean) => void; - +toggleElementInspector: () => void; - - // iOS only. - +setIsShakeToShowDevMenuEnabled: (enabled: boolean) => void; -} - -export default TurboModuleRegistry.getEnforcing('DevSettings'); From b0254e8d3cedac28cb58846af1a7ebc2e4a10575 Mon Sep 17 00:00:00 2001 From: Petr Nikolaev Date: Fri, 31 May 2019 06:32:39 -0700 Subject: [PATCH 052/330] Revert D15551356: [react-native][PR] [TM] Add spec for UIManager Differential Revision: D15551356 Original commit changeset: 076c4ce635aa fbshipit-source-id: dff59dc9c98bc579851091855611ee5d973931d0 --- .../AccessibilityInfo.android.js | 2 +- Libraries/ReactNative/NativeUIManager.js | 122 ---------------- Libraries/ReactNative/UIManager.js | 131 +++++++----------- Libraries/ReactNative/UIManagerStatTracker.js | 4 +- .../getNativeComponentAttributes.js | 7 +- 5 files changed, 53 insertions(+), 213 deletions(-) delete mode 100644 Libraries/ReactNative/NativeUIManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index 5c9ab848d2ecff..ff9a7329a56c87 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -139,7 +139,7 @@ const AccessibilityInfo = { setAccessibilityFocus: function(reactTag: number): void { UIManager.sendAccessibilityEvent( reactTag, - UIManager.getConstants().AccessibilityEventTypes.typeViewFocused, + UIManager.AccessibilityEventTypes.typeViewFocused, ); }, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js deleted file mode 100644 index 9eb60e68194b81..00000000000000 --- a/Libraries/ReactNative/NativeUIManager.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -import type {TurboModule} from '../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - +getConstants: () => Object; - +getConstantsForViewManager: (viewManagerName: string) => Object; - +getDefaultEventTypes: () => Array; - +playTouchSound: () => void; - +lazilyLoadView: (name: string) => Object; // revisit return - +createView: ( - reactTag: ?number, - viewName: string, - rootTag: number, - props: Object, - ) => void; - +updateView: (reactTag: number, viewName: string, props: Object) => void; - +focus: (reactTag: ?number) => void; - +blur: (reactTag: ?number) => void; - +findSubviewIn: ( - reactTag: ?number, - point: [number, number], - callback: ( - nativeViewTag: number, - left: number, - top: number, - width: number, - height: number, - ) => void, - ) => void; - +dispatchViewManagerCommand: ( - reactTag: ?number, - commandID: number, - commandArgs: ?Array, // is this best? - ) => void; - +measure: ( - reactTag: ?number, - callback: ( - left: number, - top: number, - width: number, - height: number, - pageX: number, - pageY: number, - ) => void, - ) => void; - +measureInWindow: ( - reactTag: ?number, - callback: (x: number, y: number, width: number, height: number) => void, - ) => void; - +viewIsDescendantOf: ( - reactTag: ?number, - ancestorReactTag: ?number, - callback: (result: Array) => void, - ) => void; - +measureLayout: ( - reactTag: ?number, - ancestorReactTag: ?number, - errorCallback: (error: Object) => void, - callback: ( - left: number, - top: number, - width: number, - height: number, - ) => void, - ) => void; - +measureLayoutRelativeToParent: ( - reactTag: ?number, - errorCallback: (error: Object) => void, - callback: ( - left: number, - top: number, - width: number, - height: number, - ) => void, - ) => void; - +setJSResponder: (reactTag: ?number, blockNativeResponder: boolean) => void; - +clearJSResponder: () => void; - +configureNextLayoutAnimation: ( - config: Object, - callback: () => void, // check what is returned here - errorCallback: (error: Object) => void, - ) => void; - +removeSubviewsFromContainerWithID: (containerID: number) => void; - +replaceExistingNonRootView: ( - reactTag: ?number, - newReactTag: ?number, - ) => void; - +setChildren: (containerTag: ?number, reactTags: Array) => void; - +manageChildren: ( - containerTag: ?number, - moveFromIndices: Array, - moveToIndices: Array, - addChildReactTags: Array, - addAtIndices: Array, - removeAtIndices: Array, - ) => void; - - // Android only - +setLayoutAnimationEnabledExperimental: (enabled: boolean) => void; - +sendAccessibilityEvent: (reactTag: ?number, eventType: number) => void; - +showPopupMenu: ( - reactTag: ?number, - items: Array, - error: (error: Object) => void, - success: (event: string, selected?: number) => void, - ) => void; - +dismissPopupMenu: () => void; -} - -export default TurboModuleRegistry.getEnforcing('UIManager'); diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index 234732bfe1db2c..cf7f8edbdbb839 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow + * @flow strict-local * @format */ 'use strict'; @@ -14,94 +14,58 @@ const Platform = require('../Utilities/Platform'); const UIManagerProperties = require('./UIManagerProperties'); const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty'); +const invariant = require('invariant'); -import NativeUIManager from './NativeUIManager'; -import type {Spec} from './NativeUIManager'; - +const {UIManager} = NativeModules; const viewManagerConfigs = {}; -interface UIManagerJSInterface extends Spec { - +getViewManagerConfig: (viewManagerName: string) => Object; - // The following are not marked read-only due to logic in UIManagerStatTracker. - createView: ( - reactTag: ?number, - viewName: string, - rootTag: number, - props: Object, - ) => void; - updateView: (reactTag: number, viewName: string, props: Object) => void; - manageChildren: ( - containerTag: ?number, - moveFromIndices: Array, - moveToIndices: Array, - addChildReactTags: Array, - addAtIndices: Array, - removeAtIndices: Array, - ) => void; -} +invariant( + UIManager, + 'UIManager is undefined. The native module config is probably incorrect.', +); const triedLoadingConfig = new Set(); - -let NativeUIManagerConstants = {}; -let isNativeUIManagerConstantsSet = false; -function getConstants(): Object { - if (!isNativeUIManagerConstantsSet) { - NativeUIManagerConstants = NativeUIManager.getConstants(); - isNativeUIManagerConstantsSet = true; +UIManager.getViewManagerConfig = function(viewManagerName: string) { + if ( + viewManagerConfigs[viewManagerName] === undefined && + UIManager.getConstantsForViewManager + ) { + try { + viewManagerConfigs[ + viewManagerName + ] = UIManager.getConstantsForViewManager(viewManagerName); + } catch (e) { + viewManagerConfigs[viewManagerName] = null; + } } - return NativeUIManagerConstants; -} -const UIManagerJS: UIManagerJSInterface = { - ...NativeUIManager, - getConstants(): Object { - return getConstants(); - }, - getViewManagerConfig: function(viewManagerName: string) { - if ( - viewManagerConfigs[viewManagerName] === undefined && - NativeUIManager.getConstantsForViewManager - ) { - try { - viewManagerConfigs[ - viewManagerName - ] = NativeUIManager.getConstantsForViewManager(viewManagerName); - } catch (e) { - viewManagerConfigs[viewManagerName] = null; - } - } + const config = viewManagerConfigs[viewManagerName]; + if (config) { + return config; + } - const config = viewManagerConfigs[viewManagerName]; - if (config) { + // If we're in the Chrome Debugger, let's not even try calling the sync + // method. + if (__DEV__) { + if (!global.nativeCallSyncHook) { return config; } + } - // If we're in the Chrome Debugger, let's not even try calling the sync - // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { - return config; - } - } - - if ( - NativeUIManager.lazilyLoadView && - !triedLoadingConfig.has(viewManagerName) - ) { - const result = NativeUIManager.lazilyLoadView(viewManagerName); - triedLoadingConfig.add(viewManagerName); - if (result.viewConfig) { - getConstants()[viewManagerName] = result.viewConfig; - lazifyViewManagerConfig(viewManagerName); - } + if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) { + const result = UIManager.lazilyLoadView(viewManagerName); + triedLoadingConfig.add(viewManagerName); + if (result.viewConfig) { + UIManager[viewManagerName] = result.viewConfig; + lazifyViewManagerConfig(viewManagerName); } + } - return viewManagerConfigs[viewManagerName]; - }, + return viewManagerConfigs[viewManagerName]; }; function lazifyViewManagerConfig(viewName) { - const viewConfig = getConstants()[viewName]; + const viewConfig = UIManager[viewName]; if (viewConfig.Manager) { viewManagerConfigs[viewName] = viewConfig; defineLazyObjectProperty(viewConfig, 'Constants', { @@ -142,10 +106,10 @@ function lazifyViewManagerConfig(viewName) { * namespace instead of UIManager, unlike Android. */ if (Platform.OS === 'ios') { - Object.keys(getConstants()).forEach(viewName => { + Object.keys(UIManager).forEach(viewName => { lazifyViewManagerConfig(viewName); }); -} else if (getConstants().ViewManagerNames) { +} else if (UIManager.ViewManagerNames) { // We want to add all the view managers to the UIManager. // However, the way things are set up, the list of view managers is not known at compile time. // As Prepack runs at compile it, it cannot process this loop. @@ -156,13 +120,13 @@ if (Platform.OS === 'ios') { residual( 'void', (UIManager, defineLazyObjectProperty) => { - UIManager.getConstants().ViewManagerNames.forEach(viewManagerName => { + UIManager.ViewManagerNames.forEach(viewManagerName => { defineLazyObjectProperty(UIManager, viewManagerName, { get: () => UIManager.getConstantsForViewManager(viewManagerName), }); }); }, - NativeUIManager, + UIManager, defineLazyObjectProperty, ); @@ -171,28 +135,27 @@ if (Platform.OS === 'ios') { // so that any accesses to unknown properties along the global code will fail // when Prepack encounters them. if (global.__makePartial) { - global.__makePartial(NativeUIManager); + global.__makePartial(UIManager); } } if (__DEV__) { - Object.keys(getConstants()).forEach(viewManagerName => { + Object.keys(UIManager).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { - viewManagerConfigs[viewManagerName] = getConstants()[viewManagerName]; + viewManagerConfigs[viewManagerName] = UIManager[viewManagerName]; } - defineLazyObjectProperty(NativeUIManager, viewManagerName, { + defineLazyObjectProperty(UIManager, viewManagerName, { get: () => { console.warn( `Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` + `is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`, ); - - return UIManagerJS.getViewManagerConfig(viewManagerName); + return UIManager.getViewManagerConfig(viewManagerName); }, }); } }); } -module.exports = UIManagerJS; +module.exports = UIManager; diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js index 85aaa6ba7707a7..ec1494c53b4390 100644 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ b/Libraries/ReactNative/UIManagerStatTracker.js @@ -52,8 +52,8 @@ const UIManagerStatTracker = { remove, ) { incStat('manageChildren', 1); - incStat('move', moveFrom.length); - incStat('remove', remove.length); + incStat('move', Object.keys(moveFrom || []).length); + incStat('remove', Object.keys(remove || []).length); manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove); }; }, diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index 85a347bea1f358..bf08c389eb8753 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -96,18 +96,17 @@ function attachDefaultEventTypes(viewConfig: any) { // This is supported on UIManager platforms (ex: Android), // as lazy view managers are not implemented for all platforms. // See [UIManager] for details on constants and implementations. - const constants = UIManager.getConstants(); - if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) { + if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) { // Lazy view managers enabled. viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); } else { viewConfig.bubblingEventTypes = merge( viewConfig.bubblingEventTypes, - constants.genericBubblingEventTypes, + UIManager.genericBubblingEventTypes, ); viewConfig.directEventTypes = merge( viewConfig.directEventTypes, - constants.genericDirectEventTypes, + UIManager.genericDirectEventTypes, ); } } From db7e00250c98f0d7b7b9fae5241d0ba08701e6a7 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 10:53:03 -0700 Subject: [PATCH 053/330] Reland "[react-native][PR] [TM] Add spec for DevSettings" Summary: Original commit changeset: 70b4842f5cde Reviewed By: cpojer Differential Revision: D15578852 fbshipit-source-id: 6389a6f5ed2115182d88dcc777e6457c376750f6 --- .../NativeModules/specs/NativeDevSettings.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Libraries/NativeModules/specs/NativeDevSettings.js diff --git a/Libraries/NativeModules/specs/NativeDevSettings.js b/Libraries/NativeModules/specs/NativeDevSettings.js new file mode 100644 index 00000000000000..9a53a0db7905e0 --- /dev/null +++ b/Libraries/NativeModules/specs/NativeDevSettings.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +reload: () => void; + +setHotLoadingEnabled: (isHotLoadingEnabled: boolean) => void; + +setIsDebuggingRemotely: (isDebuggingRemotelyEnabled: boolean) => void; + +setLiveReloadEnabled: (isLiveReloadEnabled: boolean) => void; + +setProfilingEnabled: (isProfilingEnabled: boolean) => void; + +toggleElementInspector: () => void; + + // iOS only. + +setIsShakeToShowDevMenuEnabled: (enabled: boolean) => void; +} + +export default TurboModuleRegistry.getEnforcing('DevSettings'); From 3b65d2c2c8ce92693abc92bd0b3ff8342ab80f3c Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 10:53:03 -0700 Subject: [PATCH 054/330] Reland "[RN] TM Spec: relax PermissionsAndroid enforcement" Summary: Original commit changeset: cb5ce87685dc Reviewed By: cpojer Differential Revision: D15578851 fbshipit-source-id: ab8cb9a14f94bbf4e850d9af91133612060e1401 --- .../NativePermissionsAndroid.js | 2 +- .../PermissionsAndroid/PermissionsAndroid.js | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index 025f9af18419b1..4212164d8baf83 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -56,4 +56,4 @@ export interface Spec extends TurboModule { ) => Promise<{[permission: PermissionType]: PermissionStatus}>; } -export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); +export default TurboModuleRegistry.get('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 1b414e71165a29..427fb21c8a1f88 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -11,10 +11,11 @@ 'use strict'; import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; -const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); import NativePermissionsAndroid from './NativePermissionsAndroid'; +import invariant from 'invariant'; + import type { PermissionStatus, PermissionType, @@ -90,6 +91,11 @@ class PermissionsAndroid { return Promise.resolve(false); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -106,6 +112,12 @@ class PermissionsAndroid { ); return Promise.resolve(false); } + + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -158,6 +170,11 @@ class PermissionsAndroid { return Promise.resolve(this.RESULTS.DENIED); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + if (rationale) { const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, @@ -197,6 +214,11 @@ class PermissionsAndroid { return Promise.resolve({}); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From dc0106e4f4ace66e54673a3550432a519d582fcf Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 31 May 2019 11:08:38 -0700 Subject: [PATCH 055/330] Do not send log messages to Metro when `Platform.isTesting` is set Summary: Ideally this should fix `//Libraries/FBReactKit:HiPriServerSnapshotTestsFacebookRedbox`. Reviewed By: PeteTheHeat Differential Revision: D15578792 fbshipit-source-id: 83dd227122170721c0f33c54e0f0e23e810569ae --- Libraries/Core/setUpDeveloperTools.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Libraries/Core/setUpDeveloperTools.js b/Libraries/Core/setUpDeveloperTools.js index da9aa45c50e457..43213cb94bb78d 100644 --- a/Libraries/Core/setUpDeveloperTools.js +++ b/Libraries/Core/setUpDeveloperTools.js @@ -9,6 +9,8 @@ */ 'use strict'; +import Platform from '../Utilities/Platform'; + /** * Sets up developer tools for React Native. * You can use this module directly, or just require InitializeCore. @@ -26,13 +28,15 @@ if (__DEV__) { JSInspector.registerAgent(require('../JSInspector/NetworkAgent')); } - const logToConsole = require('./Devtools/logToConsole'); - ['log', 'warn', 'info', 'trace'].forEach(level => { - const originalFunction = console[level]; - // $FlowFixMe Overwrite console methods - console[level] = function(...args) { - logToConsole(level, args); - originalFunction.apply(console, args); - }; - }); + if (!Platform.isTesting) { + const logToConsole = require('./Devtools/logToConsole'); + ['log', 'warn', 'info', 'trace'].forEach(level => { + const originalFunction = console[level]; + // $FlowFixMe Overwrite console methods + console[level] = function(...args) { + logToConsole(level, args); + originalFunction.apply(console, args); + }; + }); + } } From 62c605efe1a23923292f8ec4740bba8349cbcca2 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 31 May 2019 12:13:01 -0700 Subject: [PATCH 056/330] Use relative requires for most modules in react-native-implementation Summary: This continues the migration off of haste for react-native-github by changing `react-native-implementation` not to use haste. Reviewed By: JoshuaGross Differential Revision: D15575896 fbshipit-source-id: 0de7314b7d038a6d603d09ca910f84d580c5cc33 --- .../react-native-implementation.js | 178 +++++++++--------- 1 file changed, 88 insertions(+), 90 deletions(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 8e0a72c5ce0858..af54b7a6dfe017 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -10,8 +10,6 @@ 'use strict'; -/* eslint-disable @react-native-community/no-haste-imports */ - const invariant = require('invariant'); const warnOnce = require('../Utilities/warnOnce'); @@ -19,16 +17,16 @@ const warnOnce = require('../Utilities/warnOnce'); module.exports = { // Components get AccessibilityInfo() { - return require('AccessibilityInfo'); + return require('../Components/AccessibilityInfo/AccessibilityInfo'); }, get ActivityIndicator() { - return require('ActivityIndicator'); + return require('../Components/ActivityIndicator/ActivityIndicator'); }, get ART() { - return require('ReactNativeART'); + return require('../ART/ReactNativeART'); }, get Button() { - return require('Button'); + return require('../Components/Button'); }, get CheckBox() { warnOnce( @@ -37,22 +35,22 @@ module.exports = { "It can now be installed and imported from '@react-native-community/checkbox' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-checkbox', ); - return require('CheckBox'); + return require('../Components/CheckBox/CheckBox'); }, get DatePickerIOS() { - return require('DatePickerIOS'); + return require('../Components/DatePicker/DatePickerIOS'); }, get DrawerLayoutAndroid() { - return require('DrawerLayoutAndroid'); + return require('../Components/DrawerAndroid/DrawerLayoutAndroid'); }, get FlatList() { - return require('FlatList'); + return require('../Lists/FlatList'); }, get Image() { - return require('Image'); + return require('../Image/Image'); }, get ImageBackground() { - return require('ImageBackground'); + return require('../Image/ImageBackground'); }, get ImageEditor() { warnOnce( @@ -61,7 +59,7 @@ module.exports = { "It can now be installed and imported from '@react-native-community/image-editor' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-image-editor', ); - return require('ImageEditor'); + return require('../Image/ImageEditor'); }, get ImageStore() { warnOnce( @@ -71,13 +69,13 @@ module.exports = { "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" + "* react-native-fs: `readFile(filepath, 'base64')`", ); - return require('ImageStore'); + return require('../Image/ImageStore'); }, get InputAccessoryView() { - return require('InputAccessoryView'); + return require('../Components/TextInput/InputAccessoryView'); }, get KeyboardAvoidingView() { - return require('KeyboardAvoidingView'); + return require('../Components/Keyboard/KeyboardAvoidingView'); }, get MaskedViewIOS() { warnOnce( @@ -86,34 +84,34 @@ module.exports = { "It can now be installed and imported from '@react-native-community/masked-view' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-masked-view', ); - return require('MaskedViewIOS'); + return require('../Components/MaskedView/MaskedViewIOS'); }, get Modal() { - return require('Modal'); + return require('../Modal/Modal'); }, get Picker() { - return require('Picker'); + return require('../Components/Picker/Picker'); }, get PickerIOS() { - return require('PickerIOS'); + return require('../Components/Picker/PickerIOS'); }, get ProgressBarAndroid() { - return require('ProgressBarAndroid'); + return require('../Components/ProgressBarAndroid/ProgressBarAndroid'); }, get ProgressViewIOS() { - return require('ProgressViewIOS'); + return require('../Components/ProgressViewIOS/ProgressViewIOS'); }, get SafeAreaView() { - return require('SafeAreaView'); + return require('../Components/SafeAreaView/SafeAreaView'); }, get ScrollView() { - return require('ScrollView'); + return require('../Components/ScrollView/ScrollView'); }, get SectionList() { - return require('SectionList'); + return require('../Lists/SectionList'); }, get SegmentedControlIOS() { - return require('SegmentedControlIOS'); + return require('../Components/SegmentedControlIOS/SegmentedControlIOS'); }, get Slider() { warnOnce( @@ -122,40 +120,40 @@ module.exports = { "It can now be installed and imported from '@react-native-community/slider' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-slider', ); - return require('Slider'); + return require('../Components/Slider/Slider'); }, get Switch() { - return require('Switch'); + return require('../Components/Switch/Switch'); }, get RefreshControl() { - return require('RefreshControl'); + return require('../Components/RefreshControl/RefreshControl'); }, get StatusBar() { - return require('StatusBar'); + return require('../Components/StatusBar/StatusBar'); }, get Text() { - return require('Text'); + return require('../Text/Text'); }, get TextInput() { - return require('TextInput'); + return require('../Components/TextInput/TextInput'); }, get Touchable() { - return require('Touchable'); + return require('../Components/Touchable/Touchable'); }, get TouchableHighlight() { - return require('TouchableHighlight'); + return require('../Components/Touchable/TouchableHighlight'); }, get TouchableNativeFeedback() { - return require('TouchableNativeFeedback'); + return require('../Components/Touchable/TouchableNativeFeedback'); }, get TouchableOpacity() { - return require('TouchableOpacity'); + return require('../Components/Touchable/TouchableOpacity'); }, get TouchableWithoutFeedback() { - return require('TouchableWithoutFeedback'); + return require('../Components/Touchable/TouchableWithoutFeedback'); }, get View() { - return require('View'); + return require('../Components/View/View'); }, get ViewPagerAndroid() { warnOnce( @@ -164,30 +162,30 @@ module.exports = { "It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-viewpager', ); - return require('ViewPagerAndroid'); + return require('../Components/ViewPager/ViewPagerAndroid'); }, get VirtualizedList() { - return require('VirtualizedList'); + return require('../Lists/VirtualizedList'); }, get VirtualizedSectionList() { - return require('VirtualizedSectionList'); + return require('../Lists/VirtualizedSectionList'); }, // APIs get ActionSheetIOS() { - return require('ActionSheetIOS'); + return require('../ActionSheetIOS/ActionSheetIOS'); }, get Alert() { - return require('Alert'); + return require('../Alert/Alert'); }, get Animated() { - return require('Animated'); + return require('../Animated/src/Animated'); }, get AppRegistry() { - return require('AppRegistry'); + return require('../ReactNative/AppRegistry'); }, get AppState() { - return require('AppState'); + return require('../AppState/AppState'); }, get AsyncStorage() { warnOnce( @@ -196,31 +194,31 @@ module.exports = { "It can now be installed and imported from '@react-native-community/async-storage' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-async-storage', ); - return require('AsyncStorage'); + return require('../Storage/AsyncStorage'); }, get BackHandler() { - return require('BackHandler'); + return require('../Utilities/BackHandler'); }, get Clipboard() { - return require('Clipboard'); + return require('../Components/Clipboard/Clipboard'); }, get DatePickerAndroid() { - return require('DatePickerAndroid'); + return require('../Components/DatePickerAndroid/DatePickerAndroid'); }, get DeviceInfo() { - return require('NativeDeviceInfo').default; + return require('../Utilities/DeviceInfo'); }, get Dimensions() { - return require('Dimensions'); + return require('../Utilities/Dimensions'); }, get Easing() { - return require('Easing'); + return require('../Animated/src/Easing'); }, get findNodeHandle() { - return require('ReactNative').findNodeHandle; + return require('../Renderer/shims/ReactNative').findNodeHandle; }, get I18nManager() { - return require('I18nManager'); + return require('../ReactNative/I18nManager'); }, get ImagePickerIOS() { warnOnce( @@ -230,34 +228,34 @@ module.exports = { "If you cannot upgrade to a different library, please install the deprecated '@react-native-community/image-picker-ios' package. " + 'See https://github.com/react-native-community/react-native-image-picker-ios', ); - return require('ImagePickerIOS'); + return require('../Image/ImagePickerIOS'); }, get InteractionManager() { - return require('InteractionManager'); + return require('../Interaction/InteractionManager'); }, get Keyboard() { - return require('Keyboard'); + return require('../Components/Keyboard/Keyboard'); }, get LayoutAnimation() { - return require('LayoutAnimation'); + return require('../LayoutAnimation/LayoutAnimation'); }, get Linking() { - return require('Linking'); + return require('../Linking/Linking'); }, get NativeDialogManagerAndroid() { - return require('NativeDialogManagerAndroid').default; + return require('../NativeModules/specs/NativeDialogManagerAndroid').default; }, get NativeEventEmitter() { - return require('NativeEventEmitter'); + return require('../EventEmitter/NativeEventEmitter'); }, get PanResponder() { - return require('PanResponder'); + return require('../Interaction/PanResponder'); }, get PermissionsAndroid() { - return require('PermissionsAndroid'); + return require('../PermissionsAndroid/PermissionsAndroid'); }, get PixelRatio() { - return require('PixelRatio'); + return require('../Utilities/PixelRatio'); }, get PushNotificationIOS() { warnOnce( @@ -266,83 +264,83 @@ module.exports = { "It can now be installed and imported from '@react-native-community/push-notification-ios' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-push-notification-ios', ); - return require('PushNotificationIOS'); + return require('../PushNotificationIOS/PushNotificationIOS'); }, get Settings() { - return require('Settings'); + return require('../Settings/Settings'); }, get Share() { - return require('Share'); + return require('../Share/Share'); }, get StatusBarIOS() { - return require('StatusBarIOS'); + return require('../Components/StatusBar/StatusBarIOS'); }, get StyleSheet() { - return require('StyleSheet'); + return require('../StyleSheet/StyleSheet'); }, get Systrace() { - return require('Systrace'); + return require('../Performance/Systrace'); }, get TimePickerAndroid() { - return require('TimePickerAndroid'); + return require('../Components/TimePickerAndroid/TimePickerAndroid'); }, get ToastAndroid() { - return require('ToastAndroid'); + return require('../Components/ToastAndroid/ToastAndroid'); }, get TurboModuleRegistry() { - return require('TurboModuleRegistry'); + return require('../TurboModule/TurboModuleRegistry'); }, get TVEventHandler() { - return require('TVEventHandler'); + return require('../Components/AppleTV/TVEventHandler'); }, get UIManager() { - return require('UIManager'); + return require('../ReactNative/UIManager'); }, get unstable_batchedUpdates() { - return require('ReactNative').unstable_batchedUpdates; + return require('../Renderer/shims/ReactNative').unstable_batchedUpdates; }, get UTFSequence() { - return require('UTFSequence'); + return require('../UTFSequence'); }, get Vibration() { - return require('Vibration'); + return require('../Vibration/Vibration'); }, get YellowBox() { - return require('YellowBox'); + return require('../YellowBox/YellowBox'); }, // Plugins get DeviceEventEmitter() { - return require('RCTDeviceEventEmitter'); + return require('../EventEmitter/RCTDeviceEventEmitter'); }, get NativeAppEventEmitter() { - return require('RCTNativeAppEventEmitter'); + return require('../EventEmitter/RCTNativeAppEventEmitter'); }, get NativeModules() { - return require('NativeModules'); + return require('../BatchedBridge/NativeModules'); }, get Platform() { - return require('Platform'); + return require('../Utilities/Platform'); }, get processColor() { - return require('processColor'); + return require('../StyleSheet/processColor'); }, get requireNativeComponent() { - return require('requireNativeComponent'); + return require('../ReactNative/requireNativeComponent'); }, // Prop Types get ColorPropType() { - return require('DeprecatedColorPropType'); + return require('../DeprecatedPropTypes/DeprecatedColorPropType'); }, get EdgeInsetsPropType() { - return require('DeprecatedEdgeInsetsPropType'); + return require('../DeprecatedPropTypes/DeprecatedEdgeInsetsPropType'); }, get PointPropType() { - return require('DeprecatedPointPropType'); + return require('../DeprecatedPropTypes/DeprecatedPointPropType'); }, get ViewPropTypes() { - return require('DeprecatedViewPropTypes'); + return require('../DeprecatedPropTypes/DeprecatedViewPropTypes'); }, }; From 23f578779b48040760f47bbd97ca0e970c75041b Mon Sep 17 00:00:00 2001 From: Leo Natan Date: Fri, 31 May 2019 12:44:01 -0700 Subject: [PATCH 057/330] Fix incorrect unhooking for UI manager views in RCTProfileUnhookModules (#25042) Summary: This PR fixes incorrect unhooking for UI manager views in `RCTProfileUnhookModules`. `view` is actually a key, not the view itself; instead, use `viewForReactTag:` to obtain the view itself. This fixes issue #24952. ## Changelog [iOS] [Fixed] - Fix incorrect unhooking for UI manager views in `RCTProfileUnhookModules`, causing an infinite `RCTProfileTrampoline ` recursion (#24952) Pull Request resolved: https://github.com/facebook/react-native/pull/25042 Differential Revision: D15580978 Pulled By: PeteTheHeat fbshipit-source-id: 3483a7f6380b6fb1db4249374d86f692348c9aa2 --- React/Profiler/RCTProfile.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m index 98ba2e84333354..4d7460268fa4a0 100644 --- a/React/Profiler/RCTProfile.m +++ b/React/Profiler/RCTProfile.m @@ -350,7 +350,7 @@ void RCTProfileUnhookModules(RCTBridge *bridge) if ([bridge moduleIsInitialized:[RCTUIManager class]]) { dispatch_async(dispatch_get_main_queue(), ^{ for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) { - RCTProfileUnhookInstance(view); + RCTProfileUnhookInstance([bridge.uiManager viewForReactTag:view]); } dispatch_group_leave(RCTProfileGetUnhookGroup()); From 723adad4395f0eb3848dce4e56b21d81418e9a9d Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 12:53:56 -0700 Subject: [PATCH 058/330] Reland "[react-native][PR] [TM] Add spec for UIManager" Summary: Original commit changeset: dff59dc9c98b Reviewed By: JoshuaGross Differential Revision: D15579147 fbshipit-source-id: 77a58d2ab3324e243610c1a4d4ab794a7095b3ee --- .../AccessibilityInfo.android.js | 2 +- Libraries/ReactNative/NativeUIManager.js | 122 ++++++++++++++++ Libraries/ReactNative/UIManager.js | 131 +++++++++++------- Libraries/ReactNative/UIManagerStatTracker.js | 4 +- .../getNativeComponentAttributes.js | 7 +- 5 files changed, 213 insertions(+), 53 deletions(-) create mode 100644 Libraries/ReactNative/NativeUIManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index ff9a7329a56c87..5c9ab848d2ecff 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -139,7 +139,7 @@ const AccessibilityInfo = { setAccessibilityFocus: function(reactTag: number): void { UIManager.sendAccessibilityEvent( reactTag, - UIManager.AccessibilityEventTypes.typeViewFocused, + UIManager.getConstants().AccessibilityEventTypes.typeViewFocused, ); }, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js new file mode 100644 index 00000000000000..9eb60e68194b81 --- /dev/null +++ b/Libraries/ReactNative/NativeUIManager.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => Object; + +getConstantsForViewManager: (viewManagerName: string) => Object; + +getDefaultEventTypes: () => Array; + +playTouchSound: () => void; + +lazilyLoadView: (name: string) => Object; // revisit return + +createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + +updateView: (reactTag: number, viewName: string, props: Object) => void; + +focus: (reactTag: ?number) => void; + +blur: (reactTag: ?number) => void; + +findSubviewIn: ( + reactTag: ?number, + point: [number, number], + callback: ( + nativeViewTag: number, + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +dispatchViewManagerCommand: ( + reactTag: ?number, + commandID: number, + commandArgs: ?Array, // is this best? + ) => void; + +measure: ( + reactTag: ?number, + callback: ( + left: number, + top: number, + width: number, + height: number, + pageX: number, + pageY: number, + ) => void, + ) => void; + +measureInWindow: ( + reactTag: ?number, + callback: (x: number, y: number, width: number, height: number) => void, + ) => void; + +viewIsDescendantOf: ( + reactTag: ?number, + ancestorReactTag: ?number, + callback: (result: Array) => void, + ) => void; + +measureLayout: ( + reactTag: ?number, + ancestorReactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +measureLayoutRelativeToParent: ( + reactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +setJSResponder: (reactTag: ?number, blockNativeResponder: boolean) => void; + +clearJSResponder: () => void; + +configureNextLayoutAnimation: ( + config: Object, + callback: () => void, // check what is returned here + errorCallback: (error: Object) => void, + ) => void; + +removeSubviewsFromContainerWithID: (containerID: number) => void; + +replaceExistingNonRootView: ( + reactTag: ?number, + newReactTag: ?number, + ) => void; + +setChildren: (containerTag: ?number, reactTags: Array) => void; + +manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; + + // Android only + +setLayoutAnimationEnabledExperimental: (enabled: boolean) => void; + +sendAccessibilityEvent: (reactTag: ?number, eventType: number) => void; + +showPopupMenu: ( + reactTag: ?number, + items: Array, + error: (error: Object) => void, + success: (event: string, selected?: number) => void, + ) => void; + +dismissPopupMenu: () => void; +} + +export default TurboModuleRegistry.getEnforcing('UIManager'); diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index cf7f8edbdbb839..234732bfe1db2c 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict-local + * @flow * @format */ 'use strict'; @@ -14,58 +14,94 @@ const Platform = require('../Utilities/Platform'); const UIManagerProperties = require('./UIManagerProperties'); const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty'); -const invariant = require('invariant'); -const {UIManager} = NativeModules; +import NativeUIManager from './NativeUIManager'; +import type {Spec} from './NativeUIManager'; + const viewManagerConfigs = {}; -invariant( - UIManager, - 'UIManager is undefined. The native module config is probably incorrect.', -); +interface UIManagerJSInterface extends Spec { + +getViewManagerConfig: (viewManagerName: string) => Object; + // The following are not marked read-only due to logic in UIManagerStatTracker. + createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + updateView: (reactTag: number, viewName: string, props: Object) => void; + manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; +} const triedLoadingConfig = new Set(); -UIManager.getViewManagerConfig = function(viewManagerName: string) { - if ( - viewManagerConfigs[viewManagerName] === undefined && - UIManager.getConstantsForViewManager - ) { - try { - viewManagerConfigs[ - viewManagerName - ] = UIManager.getConstantsForViewManager(viewManagerName); - } catch (e) { - viewManagerConfigs[viewManagerName] = null; - } - } - const config = viewManagerConfigs[viewManagerName]; - if (config) { - return config; +let NativeUIManagerConstants = {}; +let isNativeUIManagerConstantsSet = false; +function getConstants(): Object { + if (!isNativeUIManagerConstantsSet) { + NativeUIManagerConstants = NativeUIManager.getConstants(); + isNativeUIManagerConstantsSet = true; } + return NativeUIManagerConstants; +} + +const UIManagerJS: UIManagerJSInterface = { + ...NativeUIManager, + getConstants(): Object { + return getConstants(); + }, + getViewManagerConfig: function(viewManagerName: string) { + if ( + viewManagerConfigs[viewManagerName] === undefined && + NativeUIManager.getConstantsForViewManager + ) { + try { + viewManagerConfigs[ + viewManagerName + ] = NativeUIManager.getConstantsForViewManager(viewManagerName); + } catch (e) { + viewManagerConfigs[viewManagerName] = null; + } + } - // If we're in the Chrome Debugger, let's not even try calling the sync - // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { + const config = viewManagerConfigs[viewManagerName]; + if (config) { return config; } - } - if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) { - const result = UIManager.lazilyLoadView(viewManagerName); - triedLoadingConfig.add(viewManagerName); - if (result.viewConfig) { - UIManager[viewManagerName] = result.viewConfig; - lazifyViewManagerConfig(viewManagerName); + // If we're in the Chrome Debugger, let's not even try calling the sync + // method. + if (__DEV__) { + if (!global.nativeCallSyncHook) { + return config; + } } - } - return viewManagerConfigs[viewManagerName]; + if ( + NativeUIManager.lazilyLoadView && + !triedLoadingConfig.has(viewManagerName) + ) { + const result = NativeUIManager.lazilyLoadView(viewManagerName); + triedLoadingConfig.add(viewManagerName); + if (result.viewConfig) { + getConstants()[viewManagerName] = result.viewConfig; + lazifyViewManagerConfig(viewManagerName); + } + } + + return viewManagerConfigs[viewManagerName]; + }, }; function lazifyViewManagerConfig(viewName) { - const viewConfig = UIManager[viewName]; + const viewConfig = getConstants()[viewName]; if (viewConfig.Manager) { viewManagerConfigs[viewName] = viewConfig; defineLazyObjectProperty(viewConfig, 'Constants', { @@ -106,10 +142,10 @@ function lazifyViewManagerConfig(viewName) { * namespace instead of UIManager, unlike Android. */ if (Platform.OS === 'ios') { - Object.keys(UIManager).forEach(viewName => { + Object.keys(getConstants()).forEach(viewName => { lazifyViewManagerConfig(viewName); }); -} else if (UIManager.ViewManagerNames) { +} else if (getConstants().ViewManagerNames) { // We want to add all the view managers to the UIManager. // However, the way things are set up, the list of view managers is not known at compile time. // As Prepack runs at compile it, it cannot process this loop. @@ -120,13 +156,13 @@ if (Platform.OS === 'ios') { residual( 'void', (UIManager, defineLazyObjectProperty) => { - UIManager.ViewManagerNames.forEach(viewManagerName => { + UIManager.getConstants().ViewManagerNames.forEach(viewManagerName => { defineLazyObjectProperty(UIManager, viewManagerName, { get: () => UIManager.getConstantsForViewManager(viewManagerName), }); }); }, - UIManager, + NativeUIManager, defineLazyObjectProperty, ); @@ -135,27 +171,28 @@ if (Platform.OS === 'ios') { // so that any accesses to unknown properties along the global code will fail // when Prepack encounters them. if (global.__makePartial) { - global.__makePartial(UIManager); + global.__makePartial(NativeUIManager); } } if (__DEV__) { - Object.keys(UIManager).forEach(viewManagerName => { + Object.keys(getConstants()).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { - viewManagerConfigs[viewManagerName] = UIManager[viewManagerName]; + viewManagerConfigs[viewManagerName] = getConstants()[viewManagerName]; } - defineLazyObjectProperty(UIManager, viewManagerName, { + defineLazyObjectProperty(NativeUIManager, viewManagerName, { get: () => { console.warn( `Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` + `is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`, ); - return UIManager.getViewManagerConfig(viewManagerName); + + return UIManagerJS.getViewManagerConfig(viewManagerName); }, }); } }); } -module.exports = UIManager; +module.exports = UIManagerJS; diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js index ec1494c53b4390..85aaa6ba7707a7 100644 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ b/Libraries/ReactNative/UIManagerStatTracker.js @@ -52,8 +52,8 @@ const UIManagerStatTracker = { remove, ) { incStat('manageChildren', 1); - incStat('move', Object.keys(moveFrom || []).length); - incStat('remove', Object.keys(remove || []).length); + incStat('move', moveFrom.length); + incStat('remove', remove.length); manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove); }; }, diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index bf08c389eb8753..85a347bea1f358 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -96,17 +96,18 @@ function attachDefaultEventTypes(viewConfig: any) { // This is supported on UIManager platforms (ex: Android), // as lazy view managers are not implemented for all platforms. // See [UIManager] for details on constants and implementations. - if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) { + const constants = UIManager.getConstants(); + if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) { // Lazy view managers enabled. viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); } else { viewConfig.bubblingEventTypes = merge( viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, + constants.genericBubblingEventTypes, ); viewConfig.directEventTypes = merge( viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, + constants.genericDirectEventTypes, ); } } From fd607b13048952eeaffc646b17adcaaf1cea8b4a Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 31 May 2019 15:52:40 -0700 Subject: [PATCH 059/330] Back out "[Yoga] Remove comparison to `YGUndefined` *and* `0.0f`" Summary: Original commit changeset: 13c8f24e1bc8 Reviewed By: fabiomassimo Differential Revision: D15583502 fbshipit-source-id: efc6175f6c4925a383fea723195c073f49e2eff1 --- ReactCommon/yoga/yoga/Yoga.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index da24a549fd5247..d41a12013cd75d 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -2861,8 +2861,11 @@ static void YGNodelayoutImpl( availableInnerMainDim = maxInnerMainDim; } else { if (!node->getConfig()->useLegacyStretchBehaviour && - (collectedFlexItemsValues.totalFlexGrowFactors == 0 || - node->resolveFlexGrow() == 0)) { + ((YGFloatIsUndefined( + collectedFlexItemsValues.totalFlexGrowFactors) && + collectedFlexItemsValues.totalFlexGrowFactors == 0) || + (YGFloatIsUndefined(node->resolveFlexGrow()) && + node->resolveFlexGrow() == 0))) { // If we don't have any children to flex or we can't flex the node // itself, space we've used is all space we need. Root node also // should be shrunk to minimum From 83a37b4ffa95c86486e506f0bd10c64a2377fa4c Mon Sep 17 00:00:00 2001 From: Oleg Lokhvitsky Date: Fri, 31 May 2019 16:29:13 -0700 Subject: [PATCH 060/330] Backout D15554658 Summary: It's breaking Mobile Home. We're about to have our branch cut so need master to be in a stable place. https://fb.prod.workplace.com/groups/549677545222488/permalink/1123279851195585/ Reviewed By: alsun2001 Differential Revision: D15578479 fbshipit-source-id: a7e04f03630f4950f7505d35fc74119052d23178 --- Libraries/react-native/react-native-implementation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index af54b7a6dfe017..b9b76263c375e4 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -342,6 +342,10 @@ module.exports = { get ViewPropTypes() { return require('../DeprecatedPropTypes/DeprecatedViewPropTypes'); }, + // TODO(cpojer): Temporary fix for missing Toolbar + get ToolbarAndroid() { + return require('UnimplementedView'); + }, }; if (__DEV__) { From 4a6676dc18f2781e752c2055a4206a2005940bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Fri, 31 May 2019 16:42:18 -0700 Subject: [PATCH 061/330] Cache CocoaPods specs-repo (#25095) Summary: The `test_end_to_end` job has been timing out due CocoaPods taking too long to check out the Specs repo. This repo is stored at `~/.cocoapods`, therefore by caching this folder we can keep the individual e2e test run from exceeding 10 minutes w/o output. ## Changelog [Internal] [Added] - Cache CocoaPods Pull Request resolved: https://github.com/facebook/react-native/pull/25095 Differential Revision: D15587702 Pulled By: hramos fbshipit-source-id: 6669ff09a5021f012ac8a829db70442d8f7f07e8 --- .circleci/config.yml | 24 +++++++++---- scripts/run-ci-e2e-tests.js | 70 +++++++++++-------------------------- 2 files changed, 38 insertions(+), 56 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 64630eaf6c5753..439abd9e050dd2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -59,8 +59,8 @@ commands: steps: - restore_cache: keys: - - v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} - - v2-yarn-cache-{{ arch }} + - v3-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} + - v3-yarn-cache-{{ arch }} - run: name: Run Yarn command: | @@ -72,7 +72,7 @@ commands: - save_cache: paths: - ~/.cache/yarn - key: v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} + key: v3-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} install_buck_tooling: steps: @@ -433,6 +433,13 @@ jobs: # Configure Watchman - run: touch .watchmanconfig + - restore_cache: + keys: + - v1-cocoapods-{{ checksum "template/ios/Podfile" }} + - v1-cocoapods- + + - run: pod setup + - run: name: Run Detox iOS End-to-End Tests command: yarn run build-ios-e2e && yarn run test-ios-e2e @@ -448,6 +455,11 @@ jobs: node ./scripts/run-ci-e2e-tests.js --ios --retries 3; when: always + - save_cache: + paths: + - ~/.cocoapods/repos + key: v1-cocoapods-{{ checksum "template/ios/Podfile" }} + test_js_e2e: executor: node8 steps: @@ -455,6 +467,7 @@ jobs: checkout_type: node - setup_artifacts - run_yarn + - run: sudo apt-get install rsync - run: name: Run JavaScript End-to-End Tests @@ -704,10 +717,7 @@ workflows: branches: only: /^pull\/.*$/ - # Gather coverage on master + # Gather coverage - js_coverage: requires: - setup - filters: - branches: - only: master diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index b5db0c4816802e..56b4bdc644eb88 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -30,7 +30,10 @@ const SCRIPTS = __dirname; const ROOT = path.normalize(path.join(__dirname, '..')); const tryExecNTimes = require('./try-n-times'); -const TEMP = exec('mktemp -d /tmp/react-native-XXXXXXXX').stdout.trim(); +const REACT_NATIVE_TEMP_DIR = exec( + 'mktemp -d /tmp/react-native-XXXXXXXX', +).stdout.trim(); +const REACT_NATIVE_APP_DIR = `${REACT_NATIVE_TEMP_DIR}/template`; const numberOfRetries = argv.retries || 1; let SERVER_PID; let APPIUM_PID; @@ -41,18 +44,6 @@ function describe(message) { } try { - // install CLI - const CLI_PACKAGE = 'react-native-cli'; - if (!argv['skip-cli-install']) { - describe('Instal react-native-cli'); - if (exec(`yarn global add ${CLI_PACKAGE}`).code) { - echo('Could not install react-native-cli globally.'); - echo('Run with --skip-cli-install to skip this step'); - exitCode = 1; - throw Error(exitCode); - } - } - if (argv.android) { describe('Compile Android binaries'); if ( @@ -91,41 +82,21 @@ try { throw Error(exitCode); } - const PACKAGE = path.join(ROOT, 'react-native-*.tgz'); - cd(TEMP); + const REACT_NATIVE_PACKAGE = path.join(ROOT, 'react-native-*.tgz'); - describe('Create EndToEndTest React Native app'); - if ( - tryExecNTimes( - () => { - return exec( - `${path.join( - ROOT, - '/node_modules/.bin/react-native', - )} init EndToEndTest --version ${PACKAGE} --npm`, - ).code; - }, - numberOfRetries, - () => { - rm('-rf', 'EndToEndTest'); - exec('sleep 10s'); - }, - ) - ) { - echo('Failed to execute react-native init'); - echo('Most common reason is npm registry connectivity, try again'); - exitCode = 1; - throw Error(exitCode); - } + describe('Scaffold a basic React Native app from template'); + exec(`rsync -a ${ROOT}/template ${REACT_NATIVE_TEMP_DIR}`); + cd(REACT_NATIVE_APP_DIR); const METRO_CONFIG = path.join(ROOT, 'metro.config.js'); const RN_POLYFILLS = path.join(ROOT, 'rn-get-polyfills.js'); - cp(METRO_CONFIG, 'EndToEndTest/.'); - cp(RN_POLYFILLS, 'EndToEndTest/.'); + cp(METRO_CONFIG, '.'); + cp(RN_POLYFILLS, '.'); + mv('_flowconfig', '.flowconfig'); + mv('_watchmanconfig', '.watchmanconfig'); - cd('EndToEndTest'); describe('Install React Native package'); - exec(`npm install ${PACKAGE}`); + exec(`npm install ${REACT_NATIVE_PACKAGE}`); describe('Install node_modules'); if ( @@ -142,6 +113,7 @@ try { exitCode = 1; throw Error(exitCode); } + exec('rm -rf ./node_modules/react-native/template'); if (argv.android) { describe('Install end-to-end framework'); @@ -183,7 +155,7 @@ try { APPIUM_PID = appiumProcess.pid; describe('Build the app'); - if (exec('./node_modules/.bin/react-native run-android').code) { + if (exec('react-native run-android').code) { echo('could not execute react-native run-android'); exitCode = 1; throw Error(exitCode); @@ -242,19 +214,19 @@ try { () => { let destination = 'platform=iOS Simulator,name=iPhone 6s,OS=12.2'; let sdk = 'iphonesimulator'; - let scheme = 'EndToEndTest'; + let scheme = 'HelloWorld'; if (argv.tvos) { destination = 'platform=tvOS Simulator,name=Apple TV,OS=11.4'; sdk = 'appletvsimulator'; - scheme = 'EndToEndTest-tvOS'; + scheme = 'HelloWorld-tvOS'; } return exec( [ 'xcodebuild', '-workspace', - '"EndToEndTest.xcworkspace"', + '"HelloWorld.xcworkspace"', '-destination', `"${destination}"`, '-scheme', @@ -292,7 +264,7 @@ try { describe('Test: Verify packager can generate an Android bundle'); if ( exec( - './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output android-bundle.js --platform android', + 'yarn react-native bundle --entry-file index.js --platform android --dev true --bundle-output android-bundle.js --max-workers 1', ).code ) { echo('Could not build Android bundle'); @@ -302,7 +274,7 @@ try { describe('Test: Verify packager can generate an iOS bundle'); if ( exec( - './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output ios-bundle.js --platform ios', + 'yarn react-native bundle --entry-file index.js --platform ios --dev true --bundle-output ios-bundle.js --max-workers 1', ).code ) { echo('Could not build iOS bundle'); @@ -310,7 +282,7 @@ try { throw Error(exitCode); } describe('Test: Flow check'); - if (exec(path.join(ROOT, '/node_modules/.bin/flow') + ' check').code) { + if (exec(`${ROOT}/node_modules/.bin/flow check`).code) { echo('Flow check failed.'); exitCode = 1; throw Error(exitCode); From 1dfe82d588a73280e315b6d743acdb9a71f96f52 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 16:58:54 -0700 Subject: [PATCH 062/330] UIManager: fill in getViewManagerConfig() on the NativeUIManager object Summary: Some callsites access `UIManager` from `NativeModules.UIManager` instead of importing directly from `UIManager.js`. Post TurboModule spec flow typing, we don't install `getViewManagerConfig()` on the NativeUIManager object anymore, only on the JS wrapper. So callsites not importing from `UIManager.js` will break. Example: https://github.com/react-native-community/react-native-maps/blob/dbf746d66ca1b42f2beb790bfbf4c0e3a74f3279/lib/components/decorateMapComponent.js#L32-L40 Reviewed By: JoshuaGross, mdvacca Differential Revision: D15588353 fbshipit-source-id: 2c2b497dae0660abf15acb2f944546fe03e9bb0a --- Libraries/ReactNative/UIManager.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index 234732bfe1db2c..e7dd0691724881 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -100,6 +100,13 @@ const UIManagerJS: UIManagerJSInterface = { }, }; +// TODO (T45220498): Remove this. +// 3rd party libs may be calling `NativeModules.UIManager.getViewManagerConfig()` +// instead of `UIManager.getViewManagerConfig()` off UIManager.js. +// This is a workaround for now. +// $FlowFixMe +NativeUIManager.getViewManagerConfig = UIManagerJS.getViewManagerConfig; + function lazifyViewManagerConfig(viewName) { const viewConfig = getConstants()[viewName]; if (viewConfig.Manager) { From 308d63fe938e473b6eba2cc7668f5834d96078fd Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 31 May 2019 17:01:42 -0700 Subject: [PATCH 063/330] console.log shouldn't throw warning if metro isn't running Summary: When metro is not running, D15559151 caused infinite exceptions (fetch threw an error if it couldn't connect to localhost:8081) which affected UI. Swallow those errors and everything works well, with or without metro. Reviewed By: yungsters Differential Revision: D15588623 fbshipit-source-id: d170ea82478545836a7a22a228196c9778e93ef0 --- Libraries/Core/Devtools/logToConsole.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libraries/Core/Devtools/logToConsole.js b/Libraries/Core/Devtools/logToConsole.js index ecad232cb98a63..93806e76cba53f 100644 --- a/Libraries/Core/Devtools/logToConsole.js +++ b/Libraries/Core/Devtools/logToConsole.js @@ -27,6 +27,13 @@ function logToConsole( fetch(getDevServer().url + 'log-to-console', { method: 'POST', body, + }).catch(e => { + // ...Oh well! + // If metro is running, logs should be sent to metro. + // If metro is NOT running, this will throw an exception every time... and + // those exceptions will be caught and logged, which will throw another + // exception, etc, causing infinite exception loop which affects UI perf. + // If we swallow silently here, that won't happen. }); } From 489e83d977f8c1eac55e29eb5c8d88582e1608ee Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 17:45:18 -0700 Subject: [PATCH 064/330] fix import path to not use haste (UnimplementedView) Summary: We shouldn't use Haste module import anymore... Reviewed By: yungsters Differential Revision: D15589880 fbshipit-source-id: d4598a256b6af81382427cf442099b95e69b4004 --- Libraries/react-native/react-native-implementation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index b9b76263c375e4..d3602050e7f760 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -344,7 +344,7 @@ module.exports = { }, // TODO(cpojer): Temporary fix for missing Toolbar get ToolbarAndroid() { - return require('UnimplementedView'); + return require('../Components/UnimplementedViews/UnimplementedView'); }, }; From 5e6cebe50bb38ac257094227f5db9c5defd4c0f8 Mon Sep 17 00:00:00 2001 From: mitulsavani Date: Fri, 31 May 2019 19:28:00 -0700 Subject: [PATCH 065/330] add spec for ImageStore (#25101) Summary: This PR solves part of this issue: #24875 ## Changelog [General] [Added] - add TM spec for ImageStore Pull Request resolved: https://github.com/facebook/react-native/pull/25101 Reviewed By: hramos Differential Revision: D15583463 Pulled By: fkgozali fbshipit-source-id: 17e87e8fecb35d42a981b1fb348e40d2b1e91cc6 --- Libraries/Image/ImageStore.js | 23 ++++++++----------- Libraries/Image/NativeImageStore.js | 34 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 Libraries/Image/NativeImageStore.js diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js index e011ffc8022585..7d6e7be5d6faac 100644 --- a/Libraries/Image/ImageStore.js +++ b/Libraries/Image/ImageStore.js @@ -9,8 +9,7 @@ */ 'use strict'; -const RCTImageStoreManager = require('../BatchedBridge/NativeModules') - .ImageStoreManager; +import NativeImageStore from './NativeImageStore'; const Platform = require('../Utilities/Platform'); @@ -31,8 +30,8 @@ class ImageStore { * @platform ios */ static hasImageForTag(uri: string, callback: (hasImage: boolean) => void) { - if (RCTImageStoreManager.hasImageForTag) { - RCTImageStoreManager.hasImageForTag(uri, callback); + if (NativeImageStore.hasImageForTag) { + NativeImageStore.hasImageForTag(uri, callback); } else { warnUnimplementedMethod('hasImageForTag'); } @@ -47,8 +46,8 @@ class ImageStore { * @platform ios */ static removeImageForTag(uri: string) { - if (RCTImageStoreManager.removeImageForTag) { - RCTImageStoreManager.removeImageForTag(uri); + if (NativeImageStore.removeImageForTag) { + NativeImageStore.removeImageForTag(uri); } else { warnUnimplementedMethod('removeImageForTag'); } @@ -70,12 +69,8 @@ class ImageStore { success: (uri: string) => void, failure: (error: any) => void, ) { - if (RCTImageStoreManager.addImageFromBase64) { - RCTImageStoreManager.addImageFromBase64( - base64ImageData, - success, - failure, - ); + if (NativeImageStore.addImageFromBase64) { + NativeImageStore.addImageFromBase64(base64ImageData, success, failure); } else { warnUnimplementedMethod('addImageFromBase64'); } @@ -97,8 +92,8 @@ class ImageStore { success: (base64ImageData: string) => void, failure: (error: any) => void, ) { - if (RCTImageStoreManager.getBase64ForTag) { - RCTImageStoreManager.getBase64ForTag(uri, success, failure); + if (NativeImageStore.getBase64ForTag) { + NativeImageStore.getBase64ForTag(uri, success, failure); } else { warnUnimplementedMethod('getBase64ForTag'); } diff --git a/Libraries/Image/NativeImageStore.js b/Libraries/Image/NativeImageStore.js new file mode 100644 index 00000000000000..4add169d31abec --- /dev/null +++ b/Libraries/Image/NativeImageStore.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + // Common + +getBase64ForTag: ( + uri: string, + success: (base64ImageData: string) => void, + failure: (error: Object) => void, + ) => void; + + // iOS-only + +hasImageForTag: (uri: string, callback: (hasImage: boolean) => void) => void; + +removeImageForTag: (uri: string) => void; + +addImageFromBase64: ( + base64ImageData: string, + success: (uri: string) => void, + failure: (error: Object) => void, + ) => void; +} + +export default TurboModuleRegistry.getEnforcing('ImageStoringManager'); From 18fededae085b53b01e54a7ed27e32c2318e7cae Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Fri, 31 May 2019 19:53:21 -0700 Subject: [PATCH 066/330] add spec for I18nManager (#24908) Summary: Part of #24875. ## Changelog [General] [Added] - add TM spec for I18nManager Pull Request resolved: https://github.com/facebook/react-native/pull/24908 Reviewed By: fkgozali Differential Revision: D15395163 Pulled By: RSNara fbshipit-source-id: 8fd3a5a8ce5d0f74132efff4fae7224eab03405b --- Libraries/Inspector/resolveBoxStyle.js | 6 ++-- Libraries/Modal/Modal.js | 2 +- Libraries/ReactNative/I18nManager.js | 37 ++++++++++++---------- Libraries/ReactNative/NativeI18nManager.js | 26 +++++++++++++++ jest/setup.js | 9 ++++++ 5 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 Libraries/ReactNative/NativeI18nManager.js diff --git a/Libraries/Inspector/resolveBoxStyle.js b/Libraries/Inspector/resolveBoxStyle.js index 15dfaf3061d810..1f013ed064ba3c 100644 --- a/Libraries/Inspector/resolveBoxStyle.js +++ b/Libraries/Inspector/resolveBoxStyle.js @@ -69,7 +69,8 @@ function resolveBoxStyle( const styleForEnd = style[prefix + 'End']; if (styleForEnd != null) { - if (I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL) { + const constants = I18nManager.getConstants(); + if (constants.isRTL && constants.doLeftAndRightSwapInRTL) { result.left = styleForEnd; } else { result.right = styleForEnd; @@ -78,7 +79,8 @@ function resolveBoxStyle( } const styleForStart = style[prefix + 'Start']; if (styleForStart != null) { - if (I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL) { + const constants = I18nManager.getConstants(); + if (constants.isRTL && constants.doLeftAndRightSwapInRTL) { result.right = styleForStart; } else { result.left = styleForStart; diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 40c03122bb2c14..314647a843646d 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -271,7 +271,7 @@ class Modal extends React.Component { } } -const side = I18nManager.isRTL ? 'right' : 'left'; +const side = I18nManager.getConstants().isRTL ? 'right' : 'left'; const styles = StyleSheet.create({ modal: { position: 'absolute', diff --git a/Libraries/ReactNative/I18nManager.js b/Libraries/ReactNative/I18nManager.js index da2767a842068f..e5fd02e7c13dab 100644 --- a/Libraries/ReactNative/I18nManager.js +++ b/Libraries/ReactNative/I18nManager.js @@ -9,21 +9,26 @@ */ 'use strict'; -type I18nManagerStatus = { - isRTL: boolean, - doLeftAndRightSwapInRTL: boolean, - allowRTL: (allowRTL: boolean) => {}, - forceRTL: (forceRTL: boolean) => {}, - swapLeftAndRightInRTL: (flipStyles: boolean) => {}, -}; +import NativeI18nManager from './NativeI18nManager'; -const I18nManager: I18nManagerStatus = require('../BatchedBridge/NativeModules') - .I18nManager || { - isRTL: false, - doLeftAndRightSwapInRTL: true, - allowRTL: () => {}, - forceRTL: () => {}, - swapLeftAndRightInRTL: () => {}, -}; +module.exports = { + getConstants: () => { + return NativeI18nManager.getConstants(); + }, + + allowRTL: (shouldAllow: boolean) => { + NativeI18nManager.allowRTL(shouldAllow); + }, -module.exports = I18nManager; + forceRTL: (shouldForce: boolean) => { + NativeI18nManager.forceRTL(shouldForce); + }, + + swapLeftAndRightInRTL: (flipStyles: boolean) => { + NativeI18nManager.swapLeftAndRightInRTL(flipStyles); + }, + + isRTL: NativeI18nManager.getConstants().isRTL, + doLeftAndRightSwapInRTL: NativeI18nManager.getConstants() + .doLeftAndRightSwapInRTL, +}; diff --git a/Libraries/ReactNative/NativeI18nManager.js b/Libraries/ReactNative/NativeI18nManager.js new file mode 100644 index 00000000000000..0220b2471ba486 --- /dev/null +++ b/Libraries/ReactNative/NativeI18nManager.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isRTL: boolean, + doLeftAndRightSwapInRTL: boolean, + |}; + allowRTL: (allowRTL: boolean) => void; + forceRTL: (forceRTL: boolean) => void; + swapLeftAndRightInRTL: (flipStyles: boolean) => void; +} + +export default TurboModuleRegistry.getEnforcing('I18nManager'); diff --git a/jest/setup.js b/jest/setup.js index d85849066c2d82..cdd146462fe7c0 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -312,6 +312,15 @@ jest addListener: jest.fn(), removeListeners: jest.fn(), }, + I18nManager: { + allowRTL: jest.fn(), + forceRTL: jest.fn(), + swapLeftAndRightInRTL: jest.fn(), + getConstants: () => ({ + isRTL: false, + doLeftAndRightSwapInRTL: true, + }), + }, })) .mock('../Libraries/ReactNative/requireNativeComponent', () => { const React = require('react'); From 5a8cdb4bb7736f984051a2ed346bb3a5d11f7228 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 1 Jun 2019 12:44:26 -0700 Subject: [PATCH 067/330] Fabric: Additional temporary checks in prop parsing infra Summary: While ViewConfig infra isn't perfect we need to check that for correcness. See the task for more details. Reviewed By: JoshuaGross Differential Revision: D15578675 fbshipit-source-id: c99c2be9c215e6b9d7ee8e6e50d85e822c1f007e --- ReactCommon/fabric/components/image/conversions.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/components/image/conversions.h b/ReactCommon/fabric/components/image/conversions.h index 27b4960fa97a62..e1d8593b5c3080 100644 --- a/ReactCommon/fabric/components/image/conversions.h +++ b/ReactCommon/fabric/components/image/conversions.h @@ -35,11 +35,18 @@ inline void fromRawValue(const RawValue &value, ImageSource &result) { } if (items.find("width") != items.end() && - items.find("height") != items.end()) { + items.find("height") != items.end() && + // The following checks have to be removed after codegen is shipped. + // See T45151459. + items.at("width").hasType() && + items.at("height").hasType()) { result.size = {(Float)items.at("width"), (Float)items.at("height")}; } - if (items.find("scale") != items.end()) { + if (items.find("scale") != items.end() && + // The following checks have to be removed after codegen is shipped. + // See T45151459. + items.at("scale").hasType()) { result.scale = (Float)items.at("scale"); } else { result.scale = items.find("deprecated") != items.end() ? 0.0 : 1.0; From a2913d33a66dc1d179ced170d6c73c8ddf91960e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 1 Jun 2019 20:04:27 -0700 Subject: [PATCH 068/330] Fabric: The second attempt to fix a thread-safety issue in RCTNativeAnimatedModule Summary: Previously we tried to fix that with RCTUnsafeExecuteOnUIManagerQueueSync but that caused a deadlock (yeah, it's actually unsafe). Besides that, I tried to solve that with introducing a mutex that covers access to `_operations` and `_preOperations` but failed miserably. It solved threading issue but that didn't fix data-races and inconsistency of the collections. Reviewed By: sahrens Differential Revision: D15587564 fbshipit-source-id: d1953036b09354d1663a9b191440f8b4a4e6be9d --- .../NativeAnimation/RCTNativeAnimatedModule.m | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedModule.m b/Libraries/NativeAnimation/RCTNativeAnimatedModule.m index 69bf078f804a6a..0bbc9c78711625 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedModule.m +++ b/Libraries/NativeAnimation/RCTNativeAnimatedModule.m @@ -232,27 +232,31 @@ - (void)flushOperationQueues - (void)willMountComponentsWithRootTag:(NSInteger)rootTag { RCTAssertMainQueue(); - __block NSArray *preOperations; - RCTUnsafeExecuteOnUIManagerQueueSync(^{ - preOperations = self->_preOperations; + RCTExecuteOnUIManagerQueue(^{ + NSArray *preOperations = self->_preOperations; self->_preOperations = [NSMutableArray new]; + + RCTExecuteOnMainQueue(^{ + for (AnimatedOperation preOperation in preOperations) { + preOperation(self->_nodesManager); + } + }); }); - for (AnimatedOperation operation in preOperations) { - operation(self->_nodesManager); - } } - (void)didMountComponentsWithRootTag:(NSInteger)rootTag { RCTAssertMainQueue(); - __block NSArray *operations; - RCTUnsafeExecuteOnUIManagerQueueSync(^{ - operations = self->_operations; + RCTExecuteOnUIManagerQueue(^{ + NSArray *operations = self->_operations; self->_operations = [NSMutableArray new]; + + RCTExecuteOnMainQueue(^{ + for (AnimatedOperation operation in operations) { + operation(self->_nodesManager); + } + }); }); - for (AnimatedOperation operation in operations) { - operation(self->_nodesManager); - } } #pragma mark - RCTUIManagerObserver From bc6dd6b48a51abec0784dce7dc59e51d643d9604 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Sat, 1 Jun 2019 23:22:53 -0700 Subject: [PATCH 069/330] TM Spec: fixed ImageStoreManager name Summary: It used a wrong name, so this fixed the module lookup. Reviewed By: yungsters Differential Revision: D15595099 fbshipit-source-id: f5a711f595d9630541ae08339aa1532ed1d4d5f2 --- Libraries/Image/NativeImageStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Image/NativeImageStore.js b/Libraries/Image/NativeImageStore.js index 4add169d31abec..0bc4948f1fb0a8 100644 --- a/Libraries/Image/NativeImageStore.js +++ b/Libraries/Image/NativeImageStore.js @@ -31,4 +31,4 @@ export interface Spec extends TurboModule { ) => void; } -export default TurboModuleRegistry.getEnforcing('ImageStoringManager'); +export default TurboModuleRegistry.getEnforcing('ImageStoreManager'); From 9a053fc4db1d926824cf579cbfcabcd664618f9b Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sun, 2 Jun 2019 16:00:54 -0700 Subject: [PATCH 070/330] Create base MapBuffer class and tests Summary: This diff creates the base classes for MapBuffer and its tests Reviewed By: shergin Differential Revision: D15550730 fbshipit-source-id: a5a47edebd7c3e1b8b2c3ad2006aee0f8bdb7866 --- ReactCommon/fabric/mapbuffer/MapBuffer.cpp | 18 +++++++++ ReactCommon/fabric/mapbuffer/MapBuffer.h | 37 +++++++++++++++++++ .../fabric/mapbuffer/tests/MapBufferTest.cpp | 14 +++++++ 3 files changed, 69 insertions(+) create mode 100644 ReactCommon/fabric/mapbuffer/MapBuffer.cpp create mode 100644 ReactCommon/fabric/mapbuffer/MapBuffer.h create mode 100644 ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp diff --git a/ReactCommon/fabric/mapbuffer/MapBuffer.cpp b/ReactCommon/fabric/mapbuffer/MapBuffer.cpp new file mode 100644 index 00000000000000..330890f8832d55 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/MapBuffer.cpp @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "MapBuffer.h" + +namespace facebook { +namespace react { + +MapBuffer::MapBuffer() {} + +MapBuffer::~MapBuffer() {} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/mapbuffer/MapBuffer.h b/ReactCommon/fabric/mapbuffer/MapBuffer.h new file mode 100644 index 00000000000000..e92a6f40635ac8 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/MapBuffer.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook { +namespace react { + +/** + * MapBuffer is an optimized map format for transferring data like props between + * C++ and other platforms The implemenation of this map is optimized to: + * - be compact to optimize space when sparse (sparse is the common case). + * - be accessible through JNI with zero/minimal copying via ByteBuffer. + * - be Have excellent C++ single-write and many-read performance by maximizing + * CPU cache performance through compactness, data locality, and fixed offsets + * where possible. + * - be optimized for iteration and intersection against other maps, but with + * reasonably good random access as well. + * - Work recursively for nested maps/arrays. + * - Supports dynamic types that map to JSON. + * - Don't require mutability - single-write on creation. + * - have minimal APK size and build time impact. + */ +class MapBuffer { + public: + MapBuffer(); + virtual ~MapBuffer(); +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp b/ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp new file mode 100644 index 00000000000000..591f24f22cf813 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +TEST(MapBufferTest, testSomething) { + // TODO +} From 1148c03f6f51329710e23fba99a6916fff3ba42c Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 3 Jun 2019 01:49:51 -0700 Subject: [PATCH 071/330] Fixes wrong time unit of scroll event throttle (#25098) Summary: We need to use second for calculation, so change 17ms to 0.017s instead. ## Changelog [iOS] [Fixed] - Fixes wrong time unit of scroll event throttle Pull Request resolved: https://github.com/facebook/react-native/pull/25098 Reviewed By: sahrens, cpojer Differential Revision: D15576526 Pulled By: sammy-SC fbshipit-source-id: ddd8dd9098cbe582c6923ce8466892c363c090fc --- React/Views/ScrollView/RCTScrollView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Views/ScrollView/RCTScrollView.m b/React/Views/ScrollView/RCTScrollView.m index 7e73924379f80b..0e0b882a02c826 100644 --- a/React/Views/ScrollView/RCTScrollView.m +++ b/React/Views/ScrollView/RCTScrollView.m @@ -706,10 +706,10 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView * warnings, and behave strangely (ListView works fine however), so don't fix it unless you fix that too! * * We limit the delta to 17ms so that small throttles intended to enable 60fps updates will not - * inadvertantly filter out any scroll events. + * inadvertently filter out any scroll events. */ if (_allowNextScrollNoMatterWhat || - (_scrollEventThrottle > 0 && _scrollEventThrottle < MAX(17, now - _lastScrollDispatchTime))) { + (_scrollEventThrottle > 0 && _scrollEventThrottle < MAX(0.017, now - _lastScrollDispatchTime))) { if (_DEPRECATED_sendUpdatedChildFrames) { // Calculate changed frames From b45d3b8697c6ed2ce5c6e4eac7bfd14553c79ed8 Mon Sep 17 00:00:00 2001 From: Michael Mason Date: Mon, 3 Jun 2019 06:46:45 -0700 Subject: [PATCH 072/330] - Fix missing whitespace in debug instructions (#25122) Summary: Fixes minor whitespace issue with the new new-app template. ## Changelog [Android] [Fixed] - Fix missing whitespace in debug instructions Pull Request resolved: https://github.com/facebook/react-native/pull/25122 Differential Revision: D15602100 Pulled By: cpojer fbshipit-source-id: 07c51c6359e37826941de659bcedea692ff3315a --- Libraries/NewAppScreen/components/DebugInstructions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/NewAppScreen/components/DebugInstructions.js b/Libraries/NewAppScreen/components/DebugInstructions.js index 821f7cbde710f3..3953b442d1bd57 100644 --- a/Libraries/NewAppScreen/components/DebugInstructions.js +++ b/Libraries/NewAppScreen/components/DebugInstructions.js @@ -27,7 +27,7 @@ const DebugInstructions = Platform.select({ ), default: () => ( - Press menu button or + Press menu button or{' '} Shake your device to open the React Native debug menu. From d8fa1206c3fecd494b0f6abb63c66488e6ced5e0 Mon Sep 17 00:00:00 2001 From: Dratwas Date: Mon, 3 Jun 2019 07:08:42 -0700 Subject: [PATCH 073/330] fix indexed RAM bundle (#24967) Summary: Co-Authored: zamotany With React Native 0.59.8 the app keeps crashing with indexed RAM bundle on Android with the following error: ``` 2019-05-09 11:58:06.684 2793-2856/? E/AndroidRuntime: FATAL EXCEPTION: mqt_js Process: com.ramtestapp, PID: 2793 com.facebook.jni.CppException: getPropertyAsObject: property '__fbRequireBatchedBridge' is not an Object no stack at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29) at android.os.Looper.loop(Looper.java:193) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232) at java.lang.Thread.run(Thread.java:764) ``` After investigation we found that when using any bundle, let it be non-ram, FIle RAM bundle or Index RAM bundle, the `CatalystInstanceImpl.java` is always using `loadScriptsFromAsset`, which is calling `CatalystInstanceImpl::jniLoadScriptFromAssets` in C++. This method when checking if bundle is a RAM bundle, uses `JniJSModulesUnbundle::isUnbundle` which only check for js-modules/UNBUNDLE - file generated when building File RAM bundle. There is no other logic to handle Indexed RAM bundle, so it figures that the bundle is not RAM, cause there is no js-modules/UNBUNDLE file and tries to load as regular bundle and fails. In this PR we added check if it is indexed RAM bundle in `jniLoadScriptFromAssets` and handle it if it is. ## Changelog [Android] [Fixed] fix indexed RAM bundle Solves https://github.com/facebook/react-native/issues/21282 Pull Request resolved: https://github.com/facebook/react-native/pull/24967 Differential Revision: D15575924 Pulled By: cpojer fbshipit-source-id: 5ea428e0b793edd8242243f39f933d1092b35260 --- .../jni/react/jni/CatalystInstanceImpl.cpp | 2 ++ ReactCommon/cxxreact/Instance.cpp | 18 ++++++++++ ReactCommon/cxxreact/Instance.h | 2 ++ ReactCommon/cxxreact/JSIndexedRAMBundle.cpp | 35 ++++++++++++++----- ReactCommon/cxxreact/JSIndexedRAMBundle.h | 8 +++-- 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index 06a224f457ab50..28de85f7ba2f22 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -199,6 +199,8 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets( sourceURL, loadSynchronously); return; + } else if (Instance::isIndexedRAMBundle(&script)) { + instance_->loadRAMBundleFromString(std::move(script), sourceURL); } else { instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously); } diff --git a/ReactCommon/cxxreact/Instance.cpp b/ReactCommon/cxxreact/Instance.cpp index ad5069238d6e32..81996813893b92 100644 --- a/ReactCommon/cxxreact/Instance.cpp +++ b/ReactCommon/cxxreact/Instance.cpp @@ -108,6 +108,24 @@ bool Instance::isIndexedRAMBundle(const char *sourcePath) { return parseTypeFromHeader(header) == ScriptTag::RAMBundle; } +bool Instance::isIndexedRAMBundle(std::unique_ptr* script) { + BundleHeader header; + strncpy(reinterpret_cast(&header), script->get()->c_str(), sizeof(header)); + + return parseTypeFromHeader(header) == ScriptTag::RAMBundle; +} + +void Instance::loadRAMBundleFromString(std::unique_ptr script, const std::string& sourceURL) { + auto bundle = folly::make_unique(std::move(script)); + auto startupScript = bundle->getStartupCode(); + auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle)); + loadRAMBundle( + std::move(registry), + std::move(startupScript), + sourceURL, + true); +} + void Instance::loadRAMBundleFromFile(const std::string& sourcePath, const std::string& sourceURL, bool loadSynchronously) { diff --git a/ReactCommon/cxxreact/Instance.h b/ReactCommon/cxxreact/Instance.h index b72729660ff601..b129ee7e633287 100644 --- a/ReactCommon/cxxreact/Instance.h +++ b/ReactCommon/cxxreact/Instance.h @@ -47,6 +47,8 @@ class RN_EXPORT Instance { void loadScriptFromString(std::unique_ptr string, std::string sourceURL, bool loadSynchronously); static bool isIndexedRAMBundle(const char *sourcePath); + static bool isIndexedRAMBundle(std::unique_ptr* string); + void loadRAMBundleFromString(std::unique_ptr script, const std::string& sourceURL); void loadRAMBundleFromFile(const std::string& sourcePath, const std::string& sourceURL, bool loadSynchronously); diff --git a/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp b/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp index 6c2e7e87c7eb26..65c73a11aef7c5 100644 --- a/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp +++ b/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp @@ -6,7 +6,8 @@ #include "JSIndexedRAMBundle.h" #include - +#include +#include #include namespace facebook { @@ -18,14 +19,30 @@ std::function(std::string)> JSIndexedRAMBundl }; } -JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) : - m_bundle (sourcePath, std::ios_base::in) { +JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) { + m_bundle = std::make_unique(sourcePath, std::ifstream::binary); if (!m_bundle) { throw std::ios_base::failure( folly::to("Bundle ", sourcePath, - "cannot be opened: ", m_bundle.rdstate())); + "cannot be opened: ", m_bundle->rdstate())); } + init(); +} + +JSIndexedRAMBundle::JSIndexedRAMBundle(std::unique_ptr script) { + // tmpStream is needed because m_bundle is std::istream type + // which has no member 'write' + std::unique_ptr tmpStream = std::make_unique(); + tmpStream->write(script->c_str(), script->size()); + m_bundle = std::move(tmpStream); + if (!m_bundle) { + throw std::ios_base::failure( + folly::to("Bundle from string cannot be opened: ", m_bundle->rdstate())); + } + init(); +} +void JSIndexedRAMBundle::init() { // read in magic header, number of entries, and length of the startup section uint32_t header[3]; static_assert( @@ -78,12 +95,12 @@ std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const { } void JSIndexedRAMBundle::readBundle(char *buffer, const std::streamsize bytes) const { - if (!m_bundle.read(buffer, bytes)) { - if (m_bundle.rdstate() & std::ios::eofbit) { + if (!m_bundle->read(buffer, bytes)) { + if (m_bundle->rdstate() & std::ios::eofbit) { throw std::ios_base::failure("Unexpected end of RAM Bundle file"); } throw std::ios_base::failure( - folly::to("Error reading RAM Bundle: ", m_bundle.rdstate())); + folly::to("Error reading RAM Bundle: ", m_bundle->rdstate())); } } @@ -92,9 +109,9 @@ void JSIndexedRAMBundle::readBundle( const std::streamsize bytes, const std::ifstream::pos_type position) const { - if (!m_bundle.seekg(position)) { + if (!m_bundle->seekg(position)) { throw std::ios_base::failure( - folly::to("Error reading RAM Bundle: ", m_bundle.rdstate())); + folly::to("Error reading RAM Bundle: ", m_bundle->rdstate())); } readBundle(buffer, bytes); } diff --git a/ReactCommon/cxxreact/JSIndexedRAMBundle.h b/ReactCommon/cxxreact/JSIndexedRAMBundle.h index be6b27f7a84576..2f2db3b708fc26 100644 --- a/ReactCommon/cxxreact/JSIndexedRAMBundle.h +++ b/ReactCommon/cxxreact/JSIndexedRAMBundle.h @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include @@ -24,6 +24,7 @@ class RN_EXPORT JSIndexedRAMBundle : public JSModulesUnbundle { // Throws std::runtime_error on failure. JSIndexedRAMBundle(const char *sourceURL); + JSIndexedRAMBundle(std::unique_ptr script); // Throws std::runtime_error on failure. std::unique_ptr getStartupCode(); @@ -51,14 +52,15 @@ class RN_EXPORT JSIndexedRAMBundle : public JSModulesUnbundle { } }; + void init(); std::string getModuleCode(const uint32_t id) const; void readBundle(char *buffer, const std::streamsize bytes) const; void readBundle( char *buffer, const std::streamsize bytes, - const std::ifstream::pos_type position) const; + const std::istream::pos_type position) const; - mutable std::ifstream m_bundle; + mutable std::unique_ptr m_bundle; ModuleTable m_table; size_t m_baseOffset; std::unique_ptr m_startupCode; From ebb8caa4df2b6559ae9ed7cc532c7ff5a6c17e8d Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 3 Jun 2019 07:15:13 -0700 Subject: [PATCH 074/330] Add handling for ColorArray Summary: This diff adds support for ColorArrayValue in the flow parser Reviewed By: cpojer Differential Revision: D15502923 fbshipit-source-id: 6a906b6d609168378fabeb49d0080de011a34d78 --- .../getNativeComponentAttributes.js | 5 +- Libraries/StyleSheet/StyleSheetTypes.js | 1 + Libraries/StyleSheet/processColorArray.js | 19 ++ .../src/generators/GenerateViewConfigJs.js | 168 ++++++++++-------- .../GenerateViewConfigJs-test.js.snap | 2 +- .../flow/__test_fixtures__/fixtures.js | 8 +- .../__snapshots__/parser-test.js.snap | 44 +++++ .../src/parsers/flow/props.js | 8 + 8 files changed, 176 insertions(+), 79 deletions(-) create mode 100644 Libraries/StyleSheet/processColorArray.js diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index 85a347bea1f358..9dba82c47507e4 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -17,6 +17,7 @@ const insetsDiffer = require('../Utilities/differ/insetsDiffer'); const matricesDiffer = require('../Utilities/differ/matricesDiffer'); const pointsDiffer = require('../Utilities/differ/pointsDiffer'); const processColor = require('../StyleSheet/processColor'); +const processColorArray = require('../StyleSheet/processColorArray'); const resolveAssetSource = require('../Image/resolveAssetSource'); const sizesDiffer = require('../Utilities/differ/sizesDiffer'); const invariant = require('invariant'); @@ -182,8 +183,4 @@ function getProcessorForType(typeName: string): ?(nextProp: any) => any { return null; } -function processColorArray(colors: ?Array): ?Array { - return colors == null ? null : colors.map(processColor); -} - module.exports = getNativeComponentAttributes; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 39819d5e6b4eb7..9da10526c2363e 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -13,6 +13,7 @@ const AnimatedNode = require('../Animated/src/nodes/AnimatedNode'); export type ColorValue = null | string; +export type ColorArrayValue = null | $ReadOnlyArray; export type PointValue = {| x: number, y: number, diff --git a/Libraries/StyleSheet/processColorArray.js b/Libraries/StyleSheet/processColorArray.js new file mode 100644 index 00000000000000..711dc32aee5413 --- /dev/null +++ b/Libraries/StyleSheet/processColorArray.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +const processColor = require('./processColor'); + +function processColorArray(colors: ?Array): ?Array { + return colors == null ? null : colors.map(processColor); +} + +module.exports = processColorArray; diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index 3315d1a29d1349..d5e1583ea2bccc 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -34,15 +34,12 @@ const template = ` ::_COMPONENT_CONFIG_:: `; -function getReactDiffProcessValue(prop) { - const typeAnnotation = prop.typeAnnotation; - +function getReactDiffProcessValue(typeAnnotation) { switch (typeAnnotation.type) { case 'BooleanTypeAnnotation': case 'StringTypeAnnotation': case 'Int32TypeAnnotation': case 'FloatTypeAnnotation': - case 'ArrayTypeAnnotation': case 'StringEnumTypeAnnotation': return j.literal(true); case 'NativePrimitiveTypeAnnotation': @@ -60,6 +57,25 @@ function getReactDiffProcessValue(prop) { `Received unknown native typeAnnotation: "${typeAnnotation.name}"`, ); } + case 'ArrayTypeAnnotation': + if (typeAnnotation.elementType.type === 'NativePrimitiveTypeAnnotation') { + switch (typeAnnotation.elementType.name) { + case 'ColorPrimitive': + return j.template + .expression`{ process: require('processColorArray') }`; + case 'ImageSourcePrimitive': + return j.literal(true); + case 'PointPrimitive': + return j.literal(true); + default: + throw new Error( + `Received unknown array native typeAnnotation: "${ + typeAnnotation.elementType.name + }"`, + ); + } + } + return j.literal(true); default: (typeAnnotation: empty); throw new Error( @@ -194,7 +210,7 @@ function buildViewConfig( return j.property( 'init', j.identifier(schemaProp.name), - getReactDiffProcessValue(schemaProp), + getReactDiffProcessValue(schemaProp.typeAnnotation), ); }), ...getValidAttributesForEvents(componentEvents), @@ -253,76 +269,82 @@ function buildViewConfig( module.exports = { generate(libraryName: string, schema: SchemaType): FilesOutput { - const fileName = `${libraryName}NativeViewConfig.js`; - const imports: Set = new Set(); - - imports.add( - "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", - ); - imports.add( - "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", - ); - - const moduleResults = Object.keys(schema.modules) - .map(moduleName => { - const components = schema.modules[moduleName].components; - // No components in this module - if (components == null) { - return null; - } + try { + const fileName = `${libraryName}NativeViewConfig.js`; + const imports: Set = new Set(); - return Object.keys(components) - .map(componentName => { - const component = components[componentName]; - - const compatabilityComponentName = `${ - component.isDeprecatedPaperComponentNameRCT ? 'RCT' : '' - }${componentName}`; - - const replacedTemplate = componentTemplate - .replace(/::_COMPONENT_NAME_::/g, componentName) - .replace( - /::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::/g, - compatabilityComponentName, - ) - .replace( - /::_COMPAT_COMMENT_::/g, - component.isDeprecatedPaperComponentNameRCT - ? ' // RCT prefix present for paper support' - : '', - ); - - const replacedSource: string = j - .withParser('flow')(replacedTemplate) - .find(j.Identifier, { - name: 'VIEW_CONFIG', - }) - .replaceWith( - buildViewConfig( - schema, - compatabilityComponentName, - component, - imports, - ), - ) - .toSource({quote: 'single', trailingComma: true}); - - return replacedSource; - }) - .join('\n\n'); - }) - .filter(Boolean) - .join('\n\n'); - - const replacedTemplate = template - .replace(/::_COMPONENT_CONFIG_::/g, moduleResults) - .replace( - '::_IMPORTS_::', - Array.from(imports) - .sort() - .join('\n'), + imports.add( + "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", + ); + imports.add( + "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", ); - return new Map([[fileName, replacedTemplate]]); + const moduleResults = Object.keys(schema.modules) + .map(moduleName => { + const components = schema.modules[moduleName].components; + // No components in this module + if (components == null) { + return null; + } + + return Object.keys(components) + .map(componentName => { + const component = components[componentName]; + + const compatabilityComponentName = `${ + component.isDeprecatedPaperComponentNameRCT ? 'RCT' : '' + }${componentName}`; + + const replacedTemplate = componentTemplate + .replace(/::_COMPONENT_NAME_::/g, componentName) + .replace( + /::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::/g, + compatabilityComponentName, + ) + .replace( + /::_COMPAT_COMMENT_::/g, + component.isDeprecatedPaperComponentNameRCT + ? ' // RCT prefix present for paper support' + : '', + ); + + const replacedSource: string = j + .withParser('flow')(replacedTemplate) + .find(j.Identifier, { + name: 'VIEW_CONFIG', + }) + .replaceWith( + buildViewConfig( + schema, + compatabilityComponentName, + component, + imports, + ), + ) + .toSource({quote: 'single', trailingComma: true}); + + return replacedSource; + }) + .join('\n\n'); + }) + .filter(Boolean) + .join('\n\n'); + + const replacedTemplate = template + .replace(/::_COMPONENT_CONFIG_::/g, moduleResults) + .replace( + '::_IMPORTS_::', + Array.from(imports) + .sort() + .join('\n'), + ); + + return new Map([[fileName, replacedTemplate]]); + } catch (error) { + console.error(`\nError parsing schema for ${libraryName}\n`); + console.error(JSON.stringify(schema)); + throw error; + } }, }; diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 8e7ec6e5fb590e..729bfac1050bf9 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -36,7 +36,7 @@ const ArrayPropsNativeComponentViewConfig = { disableds: true, progress: true, radii: true, - colors: true, + colors: { process: require('processColorArray') }, srcs: true, points: true, }, diff --git a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js index 5fbef12ed35c10..d971d6dba4e5dc 100644 --- a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js @@ -122,7 +122,7 @@ import type { CodegenNativeComponent, } from 'CodegenFlowtypes'; -import type {ColorValue, PointValue} from 'StyleSheetTypes'; +import type {ColorValue, ColorArrayValue, PointValue} from 'StyleSheetTypes'; import type {ImageSource} from 'ImageSource'; import type {ViewProps} from 'ViewPropTypes'; @@ -171,6 +171,12 @@ type ModuleProps = $ReadOnly<{| color_optional_value: ?ColorValue, color_optional_both?: ?ColorValue, + // ColorArrayValue props + color_array_required: ColorArrayValue, + color_array_optional_key?: ColorArrayValue, + color_array_optional_value: ?ColorArrayValue, + color_array_optional_both?: ?ColorArrayValue, + // PointValue props point_required: PointValue, point_optional_key?: PointValue, diff --git a/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap index 527f9edd44c68a..8feeb11c71c60e 100644 --- a/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap @@ -262,6 +262,50 @@ Object { "type": "NativePrimitiveTypeAnnotation", }, }, + Object { + "name": "color_array_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, Object { "name": "point_required", "optional": false, diff --git a/packages/react-native-codegen/src/parsers/flow/props.js b/packages/react-native-codegen/src/parsers/flow/props.js index e7d5e16d7daf7f..222b2ca014b12c 100644 --- a/packages/react-native-codegen/src/parsers/flow/props.js +++ b/packages/react-native-codegen/src/parsers/flow/props.js @@ -105,6 +105,14 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) { type: 'NativePrimitiveTypeAnnotation', name: 'ColorPrimitive', }; + case 'ColorArrayValue': + return { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'NativePrimitiveTypeAnnotation', + name: 'ColorPrimitive', + }, + }; case 'PointValue': return { type: 'NativePrimitiveTypeAnnotation', From 93dc403e1bf2bcfb24a4ba10e760f88f19eaf96c Mon Sep 17 00:00:00 2001 From: spdr admin Date: Mon, 3 Jun 2019 07:25:55 -0700 Subject: [PATCH 075/330] Fix RNTest TVOS target (#25110) Summary: I noticed that the RNTester-tvOS target is not compilable when I wanted to test the TVOS capacity of React Native. More specifically, the changes included in this PR are: ### RNTester-tvOS target 1. Add `AppDelegate.mm` to the target. 2. Add `.m` files under `turbomodule` to the target. 3. Add the following directories to **header search path**. ``` $(SRCROOT)/../third-party/boost_1_63_0 $(SRCROOT)/../third-party/folly-2018.10.22.00 $(SRCROOT)/../third-party/glog-0.3.5/src ``` 4. Add `RN_BUNDLE_PREFIX` to the scheme argument. 5. Add `RN_BUNDLE_PREFIX` entry to the plist file. ### React-tvOS target 1. Add `RCTCxxBridgeDelegate.h` and `JSCExecutorFactory.h` to the **Copy headers**. ## Changelog [iOS] [Fixed] - Fixed the issue that the RNTester-tvOS is not compilable. Pull Request resolved: https://github.com/facebook/react-native/pull/25110 Differential Revision: D15602450 Pulled By: cpojer fbshipit-source-id: e7eda18c8193b7d88355feafa69043ffef4a8edb --- RNTester/RNTester-tvOS/Info.plist | 2 ++ RNTester/RNTester.xcodeproj/project.pbxproj | 16 ++++++++++++++++ .../xcschemes/RNTester-tvOS.xcscheme | 4 ++++ React/React.xcodeproj/project.pbxproj | 4 ++++ 4 files changed, 26 insertions(+) diff --git a/RNTester/RNTester-tvOS/Info.plist b/RNTester/RNTester-tvOS/Info.plist index 0afedbb816c675..1f05733996acbd 100644 --- a/RNTester/RNTester-tvOS/Info.plist +++ b/RNTester/RNTester-tvOS/Info.plist @@ -31,5 +31,7 @@ UIUserInterfaceStyle Automatic + RN_BUNDLE_PREFIX + $(RN_BUNDLE_PREFIX) diff --git a/RNTester/RNTester.xcodeproj/project.pbxproj b/RNTester/RNTester.xcodeproj/project.pbxproj index 52cacf2394b200..173e82ed750f47 100644 --- a/RNTester/RNTester.xcodeproj/project.pbxproj +++ b/RNTester/RNTester.xcodeproj/project.pbxproj @@ -111,6 +111,9 @@ 3D56F9F11D6F6E9B00F53A06 /* RNTesterBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 3D13F83E1D6F6AE000E69E0E /* RNTesterBundle.bundle */; }; 3DB99D0C1BA0340600302749 /* RNTesterIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB99D0B1BA0340600302749 /* RNTesterIntegrationTests.m */; }; 3DD981D61D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js in Resources */ = {isa = PBXBuildFile; fileRef = 3DD981D51D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js */; }; + 3FCC247D22A2333F0013B22F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C60EB582264416A0018C04F /* AppDelegate.mm */; }; + 3FCC24AA22A25DF80013B22F /* RCTNativeSampleTurboModuleSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C2B71152267DB1A0066069E /* RCTNativeSampleTurboModuleSpec.mm */; }; + 3FCC24AB22A25DFF0013B22F /* RCTSampleTurboModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C2B711A2267DB1A0066069E /* RCTSampleTurboModule.mm */; }; 52C11BBB1EEACA7100C1A058 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA511EEAC9A700AC40CD /* libRCTBlob.a */; }; 52C11BE11EEACA7800C1A058 /* libRCTBlob-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA531EEAC9A700AC40CD /* libRCTBlob-tvOS.a */; }; 5C2B71672267DB1A0066069E /* RCTNativeSampleTurboModuleSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C2B71152267DB1A0066069E /* RCTNativeSampleTurboModuleSpec.mm */; }; @@ -1772,8 +1775,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3FCC24AB22A25DFF0013B22F /* RCTSampleTurboModule.mm in Sources */, 2DD323DC1DA2DDBF000FE1B8 /* FlexibleSizeExampleView.m in Sources */, 2DD323DD1DA2DDBF000FE1B8 /* UpdatePropertiesExampleView.m in Sources */, + 3FCC247D22A2333F0013B22F /* AppDelegate.mm in Sources */, + 3FCC24AA22A25DF80013B22F /* RCTNativeSampleTurboModuleSpec.mm in Sources */, 2DD323E01DA2DDBF000FE1B8 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2025,6 +2031,11 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../third-party/boost_1_63_0", + "$(SRCROOT)/../third-party/folly-2018.10.22.00", + "$(SRCROOT)/../third-party/glog-0.3.5/src", + ); INFOPLIST_FILE = "RNTester-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RNTester-tvOS"; @@ -2045,6 +2056,11 @@ COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../third-party/boost_1_63_0", + "$(SRCROOT)/../third-party/folly-2018.10.22.00", + "$(SRCROOT)/../third-party/glog-0.3.5/src", + ); INFOPLIST_FILE = "RNTester-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RNTester-tvOS"; diff --git a/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme b/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme index 0c3555d5cfc2c5..a2fbdcf6be9aed 100644 --- a/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme +++ b/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme @@ -101,6 +101,10 @@ value = "1" isEnabled = "YES"> + + diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index c04e4dd50c16c1..45439f6e31f41f 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -793,6 +793,8 @@ 3DFE0D1B1DF8575800459392 /* YGMacros.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; }; 3DFE0D1C1DF8575800459392 /* Yoga.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; }; 3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; }; + 3FCC24A822A24FCC0013B22F /* JSCExecutorFactory.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 8507BBBD21EDACC200AEAFCA /* JSCExecutorFactory.h */; }; + 3FCC24A922A24FD90013B22F /* RCTCxxBridgeDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 134D63C21F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h */; }; 4F56C93822167A4800DB9F3F /* jsi/jsilib.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsi/jsilib.h */; }; 4F56C93922167A4D00DB9F3F /* jsi/jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsi/jsilib.h */; }; 4F56C93A2216A3B700DB9F3F /* jsi/jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsi/jsilib.h */; }; @@ -1344,6 +1346,8 @@ dstPath = include/React; dstSubfolderSpec = 16; files = ( + 3FCC24A922A24FD90013B22F /* RCTCxxBridgeDelegate.h in Copy Headers */, + 3FCC24A822A24FCC0013B22F /* JSCExecutorFactory.h in Copy Headers */, 0EA924D02237686F004AB895 /* RCTSurfacePresenterStub.h in Copy Headers */, 591F78DF202ADB97004A668C /* RCTLayout.h in Copy Headers */, 59EDBCC31FDF4E55003573DE /* RCTScrollableProtocol.h in Copy Headers */, From 1e428093e2d959d415e228b1c0e12ddd569aff89 Mon Sep 17 00:00:00 2001 From: Bruno Lemos Date: Mon, 3 Jun 2019 07:30:56 -0700 Subject: [PATCH 076/330] Fix ItemSeparatorComponent's leadingItem prop not being updated (#25114) Summary: Fix https://github.com/facebook/react-native/issues/24592 Just added a `getDerivedStateFromProps`, similar to what `VirtualizedSectionList` already does: https://github.com/facebook/react-native/blob/18fededae085b53b01e54a7ed27e32c2318e7cae/Libraries/Lists/VirtualizedSectionList.js#L470-L492 ## Changelog [General] [Fixed] - Fix ItemSeparatorComponent's leadingItem prop not being updated Pull Request resolved: https://github.com/facebook/react-native/pull/25114 Differential Revision: D15602460 Pulled By: cpojer fbshipit-source-id: b16a82912fd746a956f6aa360d18ade53357f634 --- Libraries/Lists/VirtualizedList.js | 61 ++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 0281d87c8a3418..d060dbf9fa6d28 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -1667,27 +1667,36 @@ class VirtualizedList extends React.PureComponent { } } -class CellRenderer extends React.Component< - { - CellRendererComponent?: ?React.ComponentType, - ItemSeparatorComponent: ?React.ComponentType<*>, - cellKey: string, - fillRateHelper: FillRateHelper, - horizontal: ?boolean, - index: number, - inversionStyle: ViewStyleProp, - item: Item, - onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader - onUnmount: (cellKey: string) => void, - onUpdateSeparators: (cellKeys: Array, props: Object) => void, - parentProps: { - getItemLayout?: ?Function, - renderItem?: ?RenderItemType, - ListItemComponent?: ?(React.ComponentType | React.Element), - }, - prevCellKey: ?string, +type CellRendererProps = { + CellRendererComponent?: ?React.ComponentType, + ItemSeparatorComponent: ?React.ComponentType<*>, + cellKey: string, + fillRateHelper: FillRateHelper, + horizontal: ?boolean, + index: number, + inversionStyle: ViewStyleProp, + item: Item, + onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader + onUnmount: (cellKey: string) => void, + onUpdateSeparators: (cellKeys: Array, props: Object) => void, + parentProps: { + getItemLayout?: ?Function, + renderItem?: ?RenderItemType, + ListItemComponent?: ?(React.ComponentType | React.Element), }, - $FlowFixMeState, + prevCellKey: ?string, +}; + +type CellRendererState = { + separatorProps: $ReadOnly<{| + highlighted: boolean, + leadingItem: ?Item, + |}>, +}; + +class CellRenderer extends React.Component< + CellRendererProps, + CellRendererState, > { state = { separatorProps: { @@ -1702,6 +1711,18 @@ class CellRenderer extends React.Component< }), }; + static getDerivedStateFromProps( + props: CellRendererProps, + prevState: CellRendererState, + ): ?CellRendererState { + return { + separatorProps: { + ...prevState.separatorProps, + leadingItem: props.item, + }, + }; + } + getChildContext() { return { virtualizedCell: { From a98772e94c07e08074cf5a2c102fcb2055a72153 Mon Sep 17 00:00:00 2001 From: Hermanyo Date: Mon, 3 Jun 2019 07:54:53 -0700 Subject: [PATCH 077/330] more code review (#25109) Summary: ## Changelog [Internal] [Changed] - Code review Pull Request resolved: https://github.com/facebook/react-native/pull/25109 Differential Revision: D15602426 Pulled By: cpojer fbshipit-source-id: a47e3d6e0b264b24cc1106a34a7cfdafdadca799 --- .../modules/camera/CameraRollManager.java | 38 ++++++++++--------- .../modules/vibration/VibrationModule.java | 9 ++--- .../modules/websocket/WebSocketModule.java | 19 +++++++--- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java index 7356b048c19525..257802675493c2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java @@ -293,23 +293,27 @@ protected void doInBackgroundGuarded(Void... params) { selectionArgs.add(mGroupName); } - if (mAssetType.equals(ASSET_TYPE_PHOTOS)) { - selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " - + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); - } else if (mAssetType.equals(ASSET_TYPE_VIDEOS)) { - selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " - + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); - } else if (mAssetType.equals(ASSET_TYPE_ALL)) { - selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " IN (" - + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO + "," - + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE + ")"); - } else { - mPromise.reject( - ERROR_UNABLE_TO_FILTER, - "Invalid filter option: '" + mAssetType + "'. Expected one of '" - + ASSET_TYPE_PHOTOS + "', '" + ASSET_TYPE_VIDEOS + "' or '" + ASSET_TYPE_ALL + "'." - ); - return; + switch (mAssetType) { + case ASSET_TYPE_PHOTOS: + selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " + + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); + break; + case ASSET_TYPE_VIDEOS: + selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " + + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); + break; + case ASSET_TYPE_ALL: + selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " IN (" + + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO + "," + + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE + ")"); + break; + default: + mPromise.reject( + ERROR_UNABLE_TO_FILTER, + "Invalid filter option: '" + mAssetType + "'. Expected one of '" + + ASSET_TYPE_PHOTOS + "', '" + ASSET_TYPE_VIDEOS + "' or '" + ASSET_TYPE_ALL + "'." + ); + return; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java index 153f800f775f2e..161a7cc19cc574 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java @@ -42,13 +42,12 @@ public void vibrate(int duration) { @ReactMethod public void vibrateByPattern(ReadableArray pattern, int repeat) { - long[] patternLong = new long[pattern.size()]; - for (int i = 0; i < pattern.size(); i++) { - patternLong[i] = pattern.getInt(i); - } - Vibrator v = (Vibrator) getReactApplicationContext().getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { + long[] patternLong = new long[pattern.size()]; + for (int i = 0; i < pattern.size(); i++) { + patternLong[i] = pattern.getInt(i); + } v.vibrate(patternLong, repeat); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java index f28f271f7f043a..c2c4021ed3c243 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java @@ -342,12 +342,19 @@ private static String getDefaultOrigin(String uri) { String scheme = ""; URI requestURI = new URI(uri); - if (requestURI.getScheme().equals("wss")) { - scheme += "https"; - } else if (requestURI.getScheme().equals("ws")) { - scheme += "http"; - } else if (requestURI.getScheme().equals("http") || requestURI.getScheme().equals("https")) { - scheme += requestURI.getScheme(); + switch (requestURI.getScheme()) { + case "wss": + scheme += "https"; + break; + case "ws": + scheme += "http"; + break; + case "http": + case "https": + scheme += requestURI.getScheme(); + break; + default: + break; } if (requestURI.getPort() != -1) { From 7f489b63f201f65158d58ad5fe33f460938d0c74 Mon Sep 17 00:00:00 2001 From: "REDMOND\\acoates" Date: Mon, 3 Jun 2019 08:41:57 -0700 Subject: [PATCH 078/330] Move unistd.h include to cpp where its used (#25107) Summary: unistd.h isn't a header available in the windows SDK, so we can't include it from react-native-windows. I moved the usage of dup, to JSBigString.cpp in a previous PR, so this header should only be needed in the cpp file, not the header. (And react-native-windows doesn't use the cpp file) ## Changelog [Internal] [Fixed] - Header cleanup Pull Request resolved: https://github.com/facebook/react-native/pull/25107 Differential Revision: D15602265 Pulled By: cpojer fbshipit-source-id: 6a62bf8fe6758e400810f37834e8646485120d71 --- ReactCommon/cxxreact/JSBigString.cpp | 1 + ReactCommon/cxxreact/JSBigString.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/cxxreact/JSBigString.cpp b/ReactCommon/cxxreact/JSBigString.cpp index dc997d1cd5b728..d841295e323d1c 100644 --- a/ReactCommon/cxxreact/JSBigString.cpp +++ b/ReactCommon/cxxreact/JSBigString.cpp @@ -7,6 +7,7 @@ #include #include +#include #include diff --git a/ReactCommon/cxxreact/JSBigString.h b/ReactCommon/cxxreact/JSBigString.h index c4bf86fd71990e..3d07f1fda4da2f 100644 --- a/ReactCommon/cxxreact/JSBigString.h +++ b/ReactCommon/cxxreact/JSBigString.h @@ -6,7 +6,6 @@ #pragma once #include -#include #include #include From 5c2459996e3932f5fd10e8aa86e406f6ffab0d07 Mon Sep 17 00:00:00 2001 From: Alex Cohen Date: Mon, 3 Jun 2019 10:55:22 -0700 Subject: [PATCH 079/330] name background tasks Summary: [iOS] [Changed] - background tasks need names in order to track them. Reviewed By: aditya7fb Differential Revision: D15604435 fbshipit-source-id: 098e28620b75860c0e39166639399bbbcd42ff2b --- React/Modules/RCTTiming.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m index 7568dff8a58a8f..bfc31c63f78dfc 100644 --- a/React/Modules/RCTTiming.m +++ b/React/Modules/RCTTiming.m @@ -147,7 +147,7 @@ - (void)markStartOfBackgroundTaskIfNeeded if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) { __weak typeof(self) weakSelf = self; // Marks the beginning of a new long-running background task. We can run the timer in the background. - _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ + _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"rct.timing.gb.task" expirationHandler:^{ typeof(self) strongSelf = weakSelf; if (!strongSelf) { return; @@ -365,7 +365,7 @@ - (void)timerDidFire @synchronized (_timers) { _timers[callbackID] = timer; } - + if (_inBackground) { [self markStartOfBackgroundTaskIfNeeded]; [self scheduleSleepTimer:timer.target]; From d3cf756613b2c047400476678debb3706b8682f0 Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Mon, 3 Jun 2019 15:57:59 -0700 Subject: [PATCH 080/330] moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event Summary: Move PtrJNodeMap to header file so that it can be accessed in events subscribers outside yoga Reviewed By: davidaurelio Differential Revision: D15602627 fbshipit-source-id: bb5bd5bbf8dcb279f5f87a4fd7287909d4e895d8 --- .../jni/first-party/yogajni/jni/YGJNI.cpp | 28 ---------------- .../jni/first-party/yogajni/jni/YGJTypes.h | 33 +++++++++++++++++++ ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 5 +++ 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 28011661441036..c0b1a99b27d680 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -75,34 +75,6 @@ const short int LAYOUT_BORDER_START_INDEX = 14; bool useBatchingForLayoutOutputs; -class PtrJNodeMap { - using JNodeArray = JArrayClass; - std::map ptrsToIdxs_; - alias_ref javaNodes_; - -public: - PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} - PtrJNodeMap( - alias_ref nativePointers, - alias_ref javaNodes) - : javaNodes_{javaNodes} { - auto pin = nativePointers->pinCritical(); - auto ptrs = pin.get(); - for (size_t i = 0, n = pin.size(); i < n; ++i) { - ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; - } - } - - local_ref ref(YGNodeRef node) { - auto idx = ptrsToIdxs_.find(node); - if (idx == ptrsToIdxs_.end()) { - return local_ref{}; - } else { - return javaNodes_->getElement(idx->second); - } - } -}; - namespace { union YGNodeContext { diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index c2c5fc518e3070..e93d74db2dc1ee 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -6,6 +6,11 @@ */ #include #include +#include +#include + +using namespace facebook::jni; +using namespace std; struct JYogaNode : public facebook::jni::JavaClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNodeJNIBase;"; @@ -28,3 +33,31 @@ struct JYogaLogger : public facebook::jni::JavaClass { facebook::jni::alias_ref, jstring); }; + +class PtrJNodeMap { + using JNodeArray = JArrayClass; + std::map ptrsToIdxs_; + alias_ref javaNodes_; + +public: + PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} + PtrJNodeMap( + alias_ref nativePointers, + alias_ref javaNodes) + : javaNodes_{javaNodes} { + auto pin = nativePointers->pinCritical(); + auto ptrs = pin.get(); + for (size_t i = 0, n = pin.size(); i < n; ++i) { + ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; + } + } + + local_ref ref(YGNodeRef node) { + auto idx = ptrsToIdxs_.find(node); + if (idx == ptrsToIdxs_.end()) { + return local_ref{}; + } else { + return javaNodes_->getElement(idx->second); + } + } +}; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index d41a12013cd75d..7baab631e2e4be 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -4093,7 +4093,7 @@ void YGNodeCalculateLayoutWithContext( marker = nullptr; #ifdef YG_ENABLE_EVENTS - Event::publish(node); + Event::publish(node, {layoutContext}); #endif // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 578d2f3a66a5e8..1a7c881f233199 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -71,5 +71,10 @@ struct Event::TypedData { YGConfig* config; }; +template <> +struct Event::TypedData { + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From a44ab2957c6994fa44bd9644ab10da142109bab8 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 3 Jun 2019 16:11:20 -0700 Subject: [PATCH 081/330] Protect access to RCTTurboModuleCache Summary: The `_rctTurboModuleCache` `std::unordered_map` can be accessed by multiple threads at the same time via the `provideRCTTurboModule` method. Since `provideRCTTurboModule` both reads and writes to `_rctTurboModuleCache`, this is really bad because we could end up reading from `_rctTurboModuleCache` while it's in an invalid state. Therefore, in this diff, I'm making it so that only one thread at a time can enter `provideRCTTurboModule`. Reviewed By: fkgozali Differential Revision: D15609987 fbshipit-source-id: e24e1f5cc2351d8cbb820b7a97074aacd06eec9d --- .../core/platform/ios/RCTTurboModuleManager.mm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 0da68b3f3db64e..93f91f00ef7769 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -8,6 +8,7 @@ #import "RCTTurboModuleManager.h" #import +#import #import #import @@ -45,6 +46,18 @@ @implementation RCTTurboModuleManager { */ std::unordered_map> _rctTurboModuleCache; std::unordered_map> _turboModuleCache; + + /** + * _rctTurboModuleCache can be accessed by muitiple threads at once via + * the provideRCTTurboModule method. This can lead to races. Therefore, we + * need to protect access to this unordered_map. + * + * Note: + * There's no need to protect access to _turboModuleCache because that cache + * is only accessed within provideTurboModule, which is only invoked by the + * JS thread. + */ + std::mutex _rctTurboModuleCacheLock; } - (instancetype)initWithBridge:(RCTBridge *)bridge delegate:(id)delegate @@ -198,6 +211,8 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name */ - (id)provideRCTTurboModule:(const char *)moduleName { + std::lock_guard guard{_rctTurboModuleCacheLock}; + auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName); if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) { return rctTurboModuleCacheLookup->second; From 738dd65967c3426e259885f7f060b349654b1abd Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 3 Jun 2019 19:17:54 -0700 Subject: [PATCH 082/330] Use SurfaceRegistry instead of AppRegistry Summary: Right now we render a surface by calling `AppRegistry.runApplication`, but the way we do this relies on the batched bridge. For Venice (bridgeless RN) I created a new module for registering a surface called SurfaceRegistry, which uses a global variable instead of registering itself as a callable module on the bridge. If that global variable exists, we can use that to start the surface instead of calling AppRegistry. Reviewed By: sahrens Differential Revision: D15502241 fbshipit-source-id: 0b8d4677f1df41f46d84444567a30e40e21fed3d --- .../fabric/uimanager/UIManagerBinding.cpp | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index afcb6aff7d45fb..ac72b2437bef0d 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -46,14 +46,25 @@ void UIManagerBinding::startSurface( parameters["initialProps"] = initalProps; parameters["fabric"] = true; - auto module = getModule(runtime, "AppRegistry"); - auto method = module.getPropertyAsFunction(runtime, "runApplication"); + if (runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { + auto registry = + runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); + auto method = registry.getPropertyAsFunction(runtime, "renderSurface"); - method.callWithThis( - runtime, - module, - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters)}); + method.call( + runtime, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters)}); + } else { + auto module = getModule(runtime, "AppRegistry"); + auto method = module.getPropertyAsFunction(runtime, "runApplication"); + + method.callWithThis( + runtime, + module, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters)}); + } } void UIManagerBinding::stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) From 43d7664308f7521f39b5aea7d5452ef9028cc345 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 3 Jun 2019 19:53:49 -0700 Subject: [PATCH 083/330] Revert D15602627: [yoga] moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event Differential Revision: D15602627 Original commit changeset: bb5bd5bbf8dc fbshipit-source-id: 5ae08826eb706c3794c36738cb9625f82b58641e --- .../jni/first-party/yogajni/jni/YGJNI.cpp | 28 ++++++++++++++++ .../jni/first-party/yogajni/jni/YGJTypes.h | 33 ------------------- ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 5 --- 4 files changed, 29 insertions(+), 39 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index c0b1a99b27d680..28011661441036 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -75,6 +75,34 @@ const short int LAYOUT_BORDER_START_INDEX = 14; bool useBatchingForLayoutOutputs; +class PtrJNodeMap { + using JNodeArray = JArrayClass; + std::map ptrsToIdxs_; + alias_ref javaNodes_; + +public: + PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} + PtrJNodeMap( + alias_ref nativePointers, + alias_ref javaNodes) + : javaNodes_{javaNodes} { + auto pin = nativePointers->pinCritical(); + auto ptrs = pin.get(); + for (size_t i = 0, n = pin.size(); i < n; ++i) { + ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; + } + } + + local_ref ref(YGNodeRef node) { + auto idx = ptrsToIdxs_.find(node); + if (idx == ptrsToIdxs_.end()) { + return local_ref{}; + } else { + return javaNodes_->getElement(idx->second); + } + } +}; + namespace { union YGNodeContext { diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index e93d74db2dc1ee..c2c5fc518e3070 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -6,11 +6,6 @@ */ #include #include -#include -#include - -using namespace facebook::jni; -using namespace std; struct JYogaNode : public facebook::jni::JavaClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNodeJNIBase;"; @@ -33,31 +28,3 @@ struct JYogaLogger : public facebook::jni::JavaClass { facebook::jni::alias_ref, jstring); }; - -class PtrJNodeMap { - using JNodeArray = JArrayClass; - std::map ptrsToIdxs_; - alias_ref javaNodes_; - -public: - PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} - PtrJNodeMap( - alias_ref nativePointers, - alias_ref javaNodes) - : javaNodes_{javaNodes} { - auto pin = nativePointers->pinCritical(); - auto ptrs = pin.get(); - for (size_t i = 0, n = pin.size(); i < n; ++i) { - ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; - } - } - - local_ref ref(YGNodeRef node) { - auto idx = ptrsToIdxs_.find(node); - if (idx == ptrsToIdxs_.end()) { - return local_ref{}; - } else { - return javaNodes_->getElement(idx->second); - } - } -}; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 7baab631e2e4be..d41a12013cd75d 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -4093,7 +4093,7 @@ void YGNodeCalculateLayoutWithContext( marker = nullptr; #ifdef YG_ENABLE_EVENTS - Event::publish(node, {layoutContext}); + Event::publish(node); #endif // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 1a7c881f233199..578d2f3a66a5e8 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -71,10 +71,5 @@ struct Event::TypedData { YGConfig* config; }; -template <> -struct Event::TypedData { - void* layoutContext; -}; - } // namespace yoga } // namespace facebook From 22475ed38d181754d64a69f3d2143fa7d4b22a35 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 3 Jun 2019 20:51:10 -0700 Subject: [PATCH 084/330] Ensure app doesn't crash when module is absent Summary: Before we flow-typed NativeI18nManager, we defaulted the implementation of I18nManager to something safe when it wasn't available. After the flow-type, it became a requirement that NativeI18nManager be present in the app. This is leading to crashes: T45287329. This diff re-enables the defaults for I18nManager. Reviewed By: fkgozali Differential Revision: D15617660 fbshipit-source-id: c3a1c737663a1a4ceae484d0ad6cbf2bd86ffe5f --- Libraries/ReactNative/I18nManager.js | 26 ++++++++++++++++++---- Libraries/ReactNative/NativeI18nManager.js | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Libraries/ReactNative/I18nManager.js b/Libraries/ReactNative/I18nManager.js index e5fd02e7c13dab..f5616c807ae57e 100644 --- a/Libraries/ReactNative/I18nManager.js +++ b/Libraries/ReactNative/I18nManager.js @@ -11,24 +11,42 @@ import NativeI18nManager from './NativeI18nManager'; +const i18nConstants = NativeI18nManager + ? NativeI18nManager.getConstants() + : { + isRTL: false, + doLeftAndRightSwapInRTL: true, + }; + module.exports = { getConstants: () => { - return NativeI18nManager.getConstants(); + return i18nConstants; }, allowRTL: (shouldAllow: boolean) => { + if (!NativeI18nManager) { + return; + } + NativeI18nManager.allowRTL(shouldAllow); }, forceRTL: (shouldForce: boolean) => { + if (!NativeI18nManager) { + return; + } + NativeI18nManager.forceRTL(shouldForce); }, swapLeftAndRightInRTL: (flipStyles: boolean) => { + if (!NativeI18nManager) { + return; + } + NativeI18nManager.swapLeftAndRightInRTL(flipStyles); }, - isRTL: NativeI18nManager.getConstants().isRTL, - doLeftAndRightSwapInRTL: NativeI18nManager.getConstants() - .doLeftAndRightSwapInRTL, + isRTL: i18nConstants.isRTL, + doLeftAndRightSwapInRTL: i18nConstants.doLeftAndRightSwapInRTL, }; diff --git a/Libraries/ReactNative/NativeI18nManager.js b/Libraries/ReactNative/NativeI18nManager.js index 0220b2471ba486..9da9a6ade2b960 100644 --- a/Libraries/ReactNative/NativeI18nManager.js +++ b/Libraries/ReactNative/NativeI18nManager.js @@ -23,4 +23,4 @@ export interface Spec extends TurboModule { swapLeftAndRightInRTL: (flipStyles: boolean) => void; } -export default TurboModuleRegistry.getEnforcing('I18nManager'); +export default TurboModuleRegistry.get('I18nManager'); From b3a50ec0de1065c9fdc6bc8453b8534a4498058a Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Mon, 3 Jun 2019 22:58:49 -0700 Subject: [PATCH 085/330] Deploy Flow v0.100 to xplat/js Reviewed By: dsainati1 Differential Revision: D15617077 fbshipit-source-id: b88325dd80d167473d3c4cc7bb93c27ea71e654b --- .flowconfig | 2 +- .flowconfig.android | 2 +- Libraries/Lists/FlatList.js | 3 --- package.json | 2 +- .../src/cli/viewconfigs/generate-view-configs-cli.js | 6 +++--- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.flowconfig b/.flowconfig index 69e9a5aef1cdf7..2df42b89ca436c 100644 --- a/.flowconfig +++ b/.flowconfig @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.99.0 +^0.100.0 diff --git a/.flowconfig.android b/.flowconfig.android index dce8cc3e8bda53..1d47c484efc3ca 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.99.0 +^0.100.0 diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 292c6e1cc63746..3722bc1a273557 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -576,9 +576,6 @@ class FlatList extends React.PureComponent, void> { .map((it, kk) => keyExtractor(it, index * numColumns + kk)) .join(':'); } else { - /* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.63 was deployed. To see the error delete this - * comment and run Flow. */ return keyExtractor(items, index); } }; diff --git a/package.json b/package.json index 47fbc2b66db8ca..0be5ffb403a123 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "eslint-plugin-react-hooks": "^1.5.1", "eslint-plugin-react-native": "3.6.0", "eslint-plugin-relay": "1.3.0", - "flow-bin": "^0.99.0", + "flow-bin": "^0.100.0", "flow-remove-types": "1.2.3", "jest": "^24.7.1", "jest-junit": "^6.3.0", diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index 6603717369500f..2ce923a97a16ac 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -31,8 +31,8 @@ generate( fileName.endsWith(supportedFileName), ), ), - /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.99 was deployed. To see the error, delete this comment - * and run Flow. */ + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ {test: argv.test, parser: 'flow'}, ); diff --git a/template/_flowconfig b/template/_flowconfig index 2047ef0464540a..80fa55fc38a41d 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -96,4 +96,4 @@ untyped-import untyped-type-import [version] -^0.99.0 +^0.100.0 diff --git a/yarn.lock b/yarn.lock index 0eda165a2609d7..9c5859f6db42db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3202,10 +3202,10 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" -flow-bin@^0.99.0: - version "0.99.1" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.99.1.tgz#0d4f413ca84a3a95d0aa64214178684dd7c6a4c5" - integrity sha512-dipNwJlb4MsVt3IuDgPTymCNL4GFoq3pG+GbY6DmBbl0dJPWFSA383rCTmgbfFhoeJ1XCfYBan0BPryToSxiiQ== +flow-bin@^0.100.0: + version "0.100.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.100.0.tgz#729902726658cfa0a81425d6401f9625cf9f5534" + integrity sha512-jcethhgrslBJukH7Z7883ohFFpzLrdsOEwHxvn5NwuTWbNaE71GAl55/PEBRJwYpDvYkRlqgcNkANTv0x5XjqA== flow-parser@0.*: version "0.89.0" From fc6bbe62b531c99dd83e6af939ad2c0a481df02e Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Tue, 4 Jun 2019 02:04:40 -0700 Subject: [PATCH 086/330] TurboModules: ES Module Cleanup Summary: Minor cleanup of module conventions in `TurboModuleRegistry`. Reviewed By: cpojer Differential Revision: D15619210 fbshipit-source-id: 90a926f992333260eb8806b5708594c4a12e68fb --- Libraries/TurboModule/TurboModuleRegistry.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Libraries/TurboModule/TurboModuleRegistry.js b/Libraries/TurboModule/TurboModuleRegistry.js index ca64f774deceea..fcec0d8ada5eda 100644 --- a/Libraries/TurboModule/TurboModuleRegistry.js +++ b/Libraries/TurboModule/TurboModuleRegistry.js @@ -10,14 +10,13 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); - +import NativeModules from '../BatchedBridge/NativeModules'; import type {TurboModule} from './RCTExport'; import invariant from 'invariant'; const turboModuleProxy = global.__turboModuleProxy; -function get(name: string): ?T { +export function get(name: string): ?T { // Backward compatibility layer during migration. const legacyModule = NativeModules[name]; if (legacyModule != null) { @@ -32,11 +31,8 @@ function get(name: string): ?T { return null; } -function getEnforcing(name: string): T { +export function getEnforcing(name: string): T { const module = get(name); invariant(module != null, `${name} is not available in this app.`); return module; } - -export {get}; -export {getEnforcing}; From afc142bc76d5cfddcacf55a1f3770e6b6ea15996 Mon Sep 17 00:00:00 2001 From: Sharon Gong Date: Tue, 4 Jun 2019 07:02:14 -0700 Subject: [PATCH 087/330] Fix accessibilityActions accessors (#25134) Summary: The accessibilityActions accessors in UIView+React.m are not aligned with the property declaration in the header file. ## Changelog [General] [Fixed] - Fix accessibilityActions accessors Pull Request resolved: https://github.com/facebook/react-native/pull/25134 Differential Revision: D15621848 Pulled By: cpojer fbshipit-source-id: f344689292ae7988e46d0d4263980306d364366b --- React/Views/UIView+React.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Views/UIView+React.m b/React/Views/UIView+React.m index d9c4d4190ab226..a14707137cf153 100644 --- a/React/Views/UIView+React.m +++ b/React/Views/UIView+React.m @@ -297,12 +297,12 @@ - (UIView *)reactAccessibilityElement return self; } -- (NSArray *)accessibilityActions +- (NSArray *)accessibilityActions { return objc_getAssociatedObject(self, _cmd); } -- (void)setAccessibilityActions:(NSArray *)accessibilityActions +- (void)setAccessibilityActions:(NSArray *)accessibilityActions { objc_setAssociatedObject(self, @selector(accessibilityActions), accessibilityActions, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } From fd7f5bb76868dced03747a8c128600993378c2ce Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 4 Jun 2019 07:06:06 -0700 Subject: [PATCH 088/330] Keep the order of Modals that we can dismiss in sequence (#24961) Summary: Fixes https://github.com/facebook/react-native/issues/16037. We need to keep the order of Modals, if we dismiss Modal randomly(before we use hash table), some Modals may not dismiss successfully. This PR should based on https://github.com/facebook/react-native/pull/24959. ## Changelog [iOS] [Fixed] - Keep the order of Modals that we can dismiss in sequence Pull Request resolved: https://github.com/facebook/react-native/pull/24961 Differential Revision: D15621858 Pulled By: cpojer fbshipit-source-id: 964729f8f4584995f4e1dd527af4b61534d369ba --- React/Views/RCTModalHostViewManager.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m index 495b90d2dddd7e..28c1c5e9423060 100644 --- a/React/Views/RCTModalHostViewManager.m +++ b/React/Views/RCTModalHostViewManager.m @@ -49,7 +49,7 @@ @interface RCTModalHostViewManager () @implementation RCTModalHostViewManager { - NSHashTable *_hostViews; + NSPointerArray *_hostViews; } RCT_EXPORT_MODULE() @@ -59,9 +59,9 @@ - (UIView *)view RCTModalHostView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge]; view.delegate = self; if (!_hostViews) { - _hostViews = [NSHashTable weakObjectsHashTable]; + _hostViews = [NSPointerArray weakObjectsPointerArray]; } - [_hostViews addObject:view]; + [_hostViews addPointer:(__bridge void *)view]; return view; } @@ -104,7 +104,7 @@ - (void)invalidate for (RCTModalHostView *hostView in _hostViews) { [hostView invalidate]; } - [_hostViews removeAllObjects]; + _hostViews = nil; } RCT_EXPORT_VIEW_PROPERTY(animationType, NSString) From dbad0fd607890317614a60ba5a7fcf82c9e5ece1 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Tue, 4 Jun 2019 08:25:00 -0700 Subject: [PATCH 089/330] Remove TMMDelegate's dependency on ReactApplicationContext Summary: `TurboModuleManagerDelegate` is an interface used to query/create TurboModules. It doesn't need to know anything about `ReactApplicationContext`. So, I'm removing all references of `ReactApplicationContext` from this class. Reviewed By: mdvacca Differential Revision: D15590552 fbshipit-source-id: 761d3ed71f124955f9c6b997e68a7a8338182126 --- .../core/ReactPackageTurboModuleManagerDelegate.java | 2 +- .../turbomodule/core/TurboModuleManagerDelegate.java | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java index fab21c9fca327e..839ada2cf080bc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java @@ -20,7 +20,7 @@ public abstract class ReactPackageTurboModuleManagerDelegate extends TurboModule private final ReactApplicationContext mReactApplicationContext; public ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { - super(reactApplicationContext); + super(); mReactApplicationContext = reactApplicationContext; for (ReactPackage reactPackage : packages) { if (reactPackage instanceof TurboReactPackage) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java index eabeae27640b35..fda66b65a36ab4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java @@ -20,17 +20,11 @@ public abstract class TurboModuleManagerDelegate { } private final HybridData mHybridData; - private final ReactApplicationContext mReactApplicationContext; protected abstract HybridData initHybrid(); - protected TurboModuleManagerDelegate(ReactApplicationContext rac) { + protected TurboModuleManagerDelegate() { mHybridData = initHybrid(); - mReactApplicationContext = rac; - } - - protected ReactApplicationContext getReactApplicationContext() { - return mReactApplicationContext; } /** From 6b4e526b2da109a367aa0a6142feb6e4e3c2532c Mon Sep 17 00:00:00 2001 From: Kudo Chien Date: Tue, 4 Jun 2019 12:39:41 -0700 Subject: [PATCH 090/330] Add debug build support for Android native code (#25147) Summary: With JSI based architecture, there will be more and more C++ native code involved. Original NDK builder in RN only supports release build and that's not reasonable for native debugging. This change introduces a way to build native code in debuggable version. Simply add `NATIVE_BUILD_TYPE=Debug` environment variable during gradle build, e.g. `NATIVE_BUILD_TYPE=Debug ./gradlew clean :ReactAndroid:assembleDebug` ## Changelog [Android] [Added] - Add native debug build support to improve debugging DX Pull Request resolved: https://github.com/facebook/react-native/pull/25147 Differential Revision: D15628533 Pulled By: cpojer fbshipit-source-id: 8f5b54c4580824452d2a1236a7bd641889b001ec --- ReactAndroid/build.gradle | 4 ++++ ReactAndroid/src/main/jni/react/jni/Android.mk | 8 ++++++++ ReactAndroid/src/main/jni/third-party/folly/Android.mk | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 84207fb50578dc..343543143431bc 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -33,6 +33,9 @@ def dependenciesPath = System.getenv("REACT_NATIVE_DEPENDENCIES") // and the build will use that. def boostPath = dependenciesPath ?: System.getenv("REACT_NATIVE_BOOST_PATH") +// Setup build type for NDK, supported values: {debug, release} +def nativeBuildType = System.getenv("NATIVE_BUILD_TYPE") ?: "release" + task createNativeDepsDirectories { downloadsDir.mkdirs() thirdPartyNdkDir.mkdirs() @@ -225,6 +228,7 @@ task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConvers inputs.dir("src/main/java/com/facebook/react/modules/blob") outputs.dir("$buildDir/react-ndk/all") commandLine(getNdkBuildFullPath(), + "NDK_DEBUG=" + (nativeBuildType.equalsIgnoreCase("debug") ? "1" : "0"), "NDK_PROJECT_PATH=null", "NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk", "NDK_OUT=" + temporaryDir, diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 1cf03a78a5ea19..28c1fae096e7bf 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -36,6 +36,14 @@ LOCAL_MODULE := reactnativejni # Compile all local c++ files. LOCAL_SRC_FILES := $(wildcard *.cpp) +ifeq ($(APP_OPTIM),debug) + # Keep symbols by overriding the strip command invoked by ndk-build. + # Note that this will apply to all shared libraries, + # i.e. shared libraries will NOT be stripped + # even though we override it in this Android.mk + cmd-strip := +endif + # Build the files in this directory as a shared library include $(BUILD_SHARED_LIBRARY) diff --git a/ReactAndroid/src/main/jni/third-party/folly/Android.mk b/ReactAndroid/src/main/jni/third-party/folly/Android.mk index c84f2d9330b419..7da39f37737875 100644 --- a/ReactAndroid/src/main/jni/third-party/folly/Android.mk +++ b/ReactAndroid/src/main/jni/third-party/folly/Android.mk @@ -17,6 +17,14 @@ LOCAL_SRC_FILES:= \ folly/container/detail/F14Table.cpp \ folly/ScopeGuard.cpp \ +ifeq ($(APP_OPTIM),debug) + LOCAL_SRC_FILES += \ + folly/lang/Assume.cpp \ + folly/lang/SafeAssert.cpp \ + folly/FileUtil.cpp \ + folly/portability/SysUio.cpp +endif + LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) From 46c7ada535f8d87f325ccbd96c24993dd522165d Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Tue, 4 Jun 2019 12:54:59 -0700 Subject: [PATCH 091/330] Fix Xcode 11 build (#25146) Summary: Fixes build in Xcode 11 beta, the signature for `__unused` was changed. This adds a new check for the new style. ## Changelog [iOS] [Fixed] - Xcode 11 beta build Pull Request resolved: https://github.com/facebook/react-native/pull/25146 Differential Revision: D15628404 Pulled By: cpojer fbshipit-source-id: 781a188a0e1562a3316fbe62920b12b03a44e4a7 --- React/Base/RCTModuleMethod.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/React/Base/RCTModuleMethod.mm b/React/Base/RCTModuleMethod.mm index 14963b19a639a6..12a5b197ce2bf3 100644 --- a/React/Base/RCTModuleMethod.mm +++ b/React/Base/RCTModuleMethod.mm @@ -91,6 +91,7 @@ static BOOL RCTParseSelectorPart(const char **input, NSMutableString *selector) static BOOL RCTParseUnused(const char **input) { return RCTReadString(input, "__attribute__((unused))") || + RCTReadString(input, "__attribute__((__unused__))") || RCTReadString(input, "__unused"); } From f5aa52399bb8dc0f0cbc3555b298837c5616d451 Mon Sep 17 00:00:00 2001 From: Jim Berlage Date: Tue, 4 Jun 2019 13:23:31 -0700 Subject: [PATCH 092/330] Ensure that iOS uses RCT_METRO_PORT instead of hardcoded 8081 when appropriate (#25144) Summary: In environments with McAfee EPro software, port 8081 is used and cannot be unbound. (See [#20466](https://github.com/facebook/react-native/issues/20466) for a recent example issue.) Most issues can be worked around by passing a `--port` option or setting `RCT_METRO_PORT`, but there are a couple places where 8081 is hardcoded that block adoption. Right now the workaround I've seen pushed on Stack Overflow and elsewhere is to modify node_modules after a `yarn install`, so I'd like to fix it at the source. This PR changes the react "Start Packager" build step and some code in the iOS DevSupport library to read from the `RCT_METRO_PORT` variable. ## Changelog [General] [Changed] - Removed hardcoded references to port 8081 and replaced them by reading from RCT_METRO_PORT (w/ fallback to 8081) Pull Request resolved: https://github.com/facebook/react-native/pull/25144 Differential Revision: D15630119 Pulled By: cpojer fbshipit-source-id: aff5d24691e0e9892a035cfbd25330fed6441199 --- React/DevSupport/RCTInspectorDevServerHelper.mm | 8 ++++++++ React/React.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/React/DevSupport/RCTInspectorDevServerHelper.mm b/React/DevSupport/RCTInspectorDevServerHelper.mm index 0f1ada9347ad60..f813fe11bba7f0 100644 --- a/React/DevSupport/RCTInspectorDevServerHelper.mm +++ b/React/DevSupport/RCTInspectorDevServerHelper.mm @@ -33,6 +33,10 @@ static NSURL *getInspectorDeviceUrl(NSURL *bundleURL) { NSNumber *inspectorProxyPort = @8081; + NSString *inspectorProxyPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"]; + if (inspectorProxyPortStr && [inspectorProxyPortStr length] > 0) { + inspectorProxyPort = [NSNumber numberWithInt:[inspectorProxyPortStr intValue]]; + } NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@", @@ -44,6 +48,10 @@ static NSURL *getAttachDeviceUrl(NSURL *bundleURL, NSString *title) { NSNumber *metroBundlerPort = @8081; + NSString *metroBundlerPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"]; + if (metroBundlerPortStr && [metroBundlerPortStr length] > 0) { + metroBundlerPort = [NSNumber numberWithInt:[metroBundlerPortStr intValue]]; + } NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/attach-debugger-nuclide?title=%@&device=%@&app=%@", diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 45439f6e31f41f..cbb4825a0630b0 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -3979,7 +3979,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost 8081 ; then\n if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\nport=\"${RCT_METRO_PORT:-8081}\"\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost \"${port}\" ; then\n if ! curl -s \"http://localhost:${port}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${port} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; showEnvVarsInLog = 0; }; 142C4F7F1B582EA6001F0B58 /* Include RCTJSCProfiler */ = { @@ -4099,7 +4099,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost 8081 ; then\n if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\nport=\"${RCT_METRO_PORT:-8081}\"\n\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost \"${port}\" ; then\n if ! curl -s \"http://localhost:${port}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${port} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; showEnvVarsInLog = 0; }; 3D383D3E1EBD27B9005632C8 /* Install Third Party */ = { From 146d1f7578c3fcb4f4a4c49599a78ee437cf41d2 Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Tue, 4 Jun 2019 13:55:02 -0700 Subject: [PATCH 093/330] Bump Android NDK to r19c (#25140) Summary: In 2019-6-4 version of Docker Android image, we've added Android NDK r19c. So this PR will change CI to use NDK r19c. I'll create a PR to website once this merged. Note: I tried to build RN with NDK 19 while I was setting up my laptop after format, and it worked. ## Changelog [Android] [Changed] - Bump Android NDK to r19c Pull Request resolved: https://github.com/facebook/react-native/pull/25140 Differential Revision: D15631301 Pulled By: cpojer fbshipit-source-id: b9a5600df1dadeba328932b694493960b242c2f7 --- .appveyor/config.yml | 4 ++-- .circleci/config.yml | 2 +- scripts/android-setup.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor/config.yml b/.appveyor/config.yml index a30baf7582a396..ed8162cf135899 100644 --- a/.appveyor/config.yml +++ b/.appveyor/config.yml @@ -1,13 +1,13 @@ environment: ANDROID_HOME: "C:\\android-sdk-windows" - ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r17c" + ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r19c" ANDROID_BUILD_VERSION: 28 ANDROID_TOOLS_VERSION: 28.0.3 GRADLE_OPTS: -Dorg.gradle.daemon=false SDK_TOOLS_URL: https://dl.google.com/android/repository/sdk-tools-windows-3859397.zip - NDK_TOOLS_URL: https://dl.google.com/android/repository/android-ndk-r17c-windows-x86_64.zip + NDK_TOOLS_URL: https://dl.google.com/android/repository/android-ndk-r19c-windows-x86_64.zip matrix: - nodejs_version: 8 diff --git a/.circleci/config.yml b/.circleci/config.yml index 439abd9e050dd2..88bb91c0a3cfe9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,7 +23,7 @@ executors: reactnativeandroid: <<: *defaults docker: - - image: reactnativecommunity/react-native-android:2019-5-29 + - image: reactnativecommunity/react-native-android:2019-6-4 resource_class: "large" environment: - TERM: "dumb" diff --git a/scripts/android-setup.sh b/scripts/android-setup.sh index c76f520b931854..3032d0c69f2543 100755 --- a/scripts/android-setup.sh +++ b/scripts/android-setup.sh @@ -40,7 +40,7 @@ function getAndroidNDK { if [ ! -e $DEPS ]; then cd $NDK_HOME || exit echo "Downloading NDK..." - curl -o ndk.zip https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip + curl -o ndk.zip https://dl.google.com/android/repository/android-ndk-r19c-linux-x86_64.zip unzip -o -q ndk.zip echo "Installed Android NDK at $NDK_HOME" touch $DEPS From 608b1b5ea2d9861816aaf3c4289e4316d9304b87 Mon Sep 17 00:00:00 2001 From: Will Holen Date: Tue, 4 Jun 2019 14:35:01 -0700 Subject: [PATCH 094/330] Include testlib files in JSI Summary: This adds the testlib.cpp/h files to external JSI. They're in a `test/` subdirectory so that build scripts using globs like `*.cpp` won't include them. Reviewed By: mhorowitz Differential Revision: D15582281 fbshipit-source-id: 1785ee5071fcf98e92fbf3a11eddb21fe84b3799 --- ReactCommon/jsi/jsi/test/testlib.cpp | 1198 ++++++++++++++++++++++++++ ReactCommon/jsi/jsi/test/testlib.h | 48 ++ 2 files changed, 1246 insertions(+) create mode 100644 ReactCommon/jsi/jsi/test/testlib.cpp create mode 100644 ReactCommon/jsi/jsi/test/testlib.h diff --git a/ReactCommon/jsi/jsi/test/testlib.cpp b/ReactCommon/jsi/jsi/test/testlib.cpp new file mode 100644 index 00000000000000..640fb133570395 --- /dev/null +++ b/ReactCommon/jsi/jsi/test/testlib.cpp @@ -0,0 +1,1198 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace facebook::jsi; + +class JSITest : public JSITestBase {}; + +TEST_P(JSITest, RuntimeTest) { + auto v = rt.evaluateJavaScript(std::make_unique("1"), ""); + EXPECT_EQ(v.getNumber(), 1); + + rt.evaluateJavaScript(std::make_unique("x = 1"), ""); + EXPECT_EQ(rt.global().getProperty(rt, "x").getNumber(), 1); +} + +TEST_P(JSITest, PropNameIDTest) { + // This is a little weird to test, because it doesn't really exist + // in JS yet. All I can do is create them, compare them, and + // receive one as an argument to a HostObject. + + PropNameID quux = PropNameID::forAscii(rt, "quux1", 4); + PropNameID movedQuux = std::move(quux); + EXPECT_EQ(movedQuux.utf8(rt), "quux"); + movedQuux = PropNameID::forAscii(rt, "quux2"); + EXPECT_EQ(movedQuux.utf8(rt), "quux2"); + PropNameID copiedQuux = PropNameID(rt, movedQuux); + EXPECT_TRUE(PropNameID::compare(rt, movedQuux, copiedQuux)); + + EXPECT_TRUE(PropNameID::compare(rt, movedQuux, movedQuux)); + EXPECT_TRUE(PropNameID::compare( + rt, movedQuux, PropNameID::forAscii(rt, std::string("quux2")))); + EXPECT_FALSE(PropNameID::compare( + rt, movedQuux, PropNameID::forAscii(rt, std::string("foo")))); + uint8_t utf8[] = {0xF0, 0x9F, 0x86, 0x97}; + PropNameID utf8PropNameID = PropNameID::forUtf8(rt, utf8, sizeof(utf8)); + EXPECT_EQ(utf8PropNameID.utf8(rt), u8"\U0001F197"); + EXPECT_TRUE(PropNameID::compare( + rt, utf8PropNameID, PropNameID::forUtf8(rt, utf8, sizeof(utf8)))); + PropNameID nonUtf8PropNameID = PropNameID::forUtf8(rt, "meow"); + EXPECT_TRUE(PropNameID::compare( + rt, nonUtf8PropNameID, PropNameID::forAscii(rt, "meow"))); + EXPECT_EQ(nonUtf8PropNameID.utf8(rt), "meow"); + PropNameID strPropNameID = + PropNameID::forString(rt, String::createFromAscii(rt, "meow")); + EXPECT_TRUE(PropNameID::compare(rt, nonUtf8PropNameID, strPropNameID)); + + auto names = PropNameID::names( + rt, "Ala", std::string("ma"), PropNameID::forAscii(rt, "kota")); + EXPECT_EQ(names.size(), 3); + EXPECT_TRUE( + PropNameID::compare(rt, names[0], PropNameID::forAscii(rt, "Ala"))); + EXPECT_TRUE( + PropNameID::compare(rt, names[1], PropNameID::forAscii(rt, "ma"))); + EXPECT_TRUE( + PropNameID::compare(rt, names[2], PropNameID::forAscii(rt, "kota"))); +} + +TEST_P(JSITest, StringTest) { + EXPECT_TRUE(checkValue(String::createFromAscii(rt, "foobar", 3), "'foo'")); + EXPECT_TRUE(checkValue(String::createFromAscii(rt, "foobar"), "'foobar'")); + + std::string baz = "baz"; + EXPECT_TRUE(checkValue(String::createFromAscii(rt, baz), "'baz'")); + + uint8_t utf8[] = {0xF0, 0x9F, 0x86, 0x97}; + EXPECT_TRUE(checkValue( + String::createFromUtf8(rt, utf8, sizeof(utf8)), "'\\uD83C\\uDD97'")); + + EXPECT_EQ(eval("'quux'").getString(rt).utf8(rt), "quux"); + EXPECT_EQ(eval("'\\u20AC'").getString(rt).utf8(rt), "\xe2\x82\xac"); + + String quux = String::createFromAscii(rt, "quux"); + String movedQuux = std::move(quux); + EXPECT_EQ(movedQuux.utf8(rt), "quux"); + movedQuux = String::createFromAscii(rt, "quux2"); + EXPECT_EQ(movedQuux.utf8(rt), "quux2"); +} + +TEST_P(JSITest, ObjectTest) { + eval("x = {1:2, '3':4, 5:'six', 'seven':['eight', 'nine']}"); + Object x = rt.global().getPropertyAsObject(rt, "x"); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 4); + EXPECT_TRUE(x.hasProperty(rt, "1")); + EXPECT_TRUE(x.hasProperty(rt, PropNameID::forAscii(rt, "1"))); + EXPECT_FALSE(x.hasProperty(rt, "2")); + EXPECT_FALSE(x.hasProperty(rt, PropNameID::forAscii(rt, "2"))); + EXPECT_TRUE(x.hasProperty(rt, "3")); + EXPECT_TRUE(x.hasProperty(rt, PropNameID::forAscii(rt, "3"))); + EXPECT_TRUE(x.hasProperty(rt, "seven")); + EXPECT_TRUE(x.hasProperty(rt, PropNameID::forAscii(rt, "seven"))); + EXPECT_EQ(x.getProperty(rt, "1").getNumber(), 2); + EXPECT_EQ(x.getProperty(rt, PropNameID::forAscii(rt, "1")).getNumber(), 2); + EXPECT_EQ(x.getProperty(rt, "3").getNumber(), 4); + Value five = 5; + EXPECT_EQ( + x.getProperty(rt, PropNameID::forString(rt, five.toString(rt))) + .getString(rt) + .utf8(rt), + "six"); + + x.setProperty(rt, "ten", 11); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 5); + EXPECT_TRUE(eval("x.ten == 11").getBool()); + + x.setProperty(rt, "e_as_float", 2.71f); + EXPECT_TRUE(eval("Math.abs(x.e_as_float - 2.71) < 0.001").getBool()); + + x.setProperty(rt, "e_as_double", 2.71); + EXPECT_TRUE(eval("x.e_as_double == 2.71").getBool()); + + uint8_t utf8[] = {0xF0, 0x9F, 0x86, 0x97}; + String nonAsciiName = String::createFromUtf8(rt, utf8, sizeof(utf8)); + x.setProperty(rt, PropNameID::forString(rt, nonAsciiName), "emoji"); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 8); + EXPECT_TRUE(eval("x['\\uD83C\\uDD97'] == 'emoji'").getBool()); + + Object seven = x.getPropertyAsObject(rt, "seven"); + EXPECT_TRUE(seven.isArray(rt)); + Object evalf = rt.global().getPropertyAsObject(rt, "eval"); + EXPECT_TRUE(evalf.isFunction(rt)); + + Object movedX = Object(rt); + movedX = std::move(x); + EXPECT_EQ(movedX.getPropertyNames(rt).size(rt), 8); + EXPECT_EQ(movedX.getProperty(rt, "1").getNumber(), 2); + + Object obj = Object(rt); + obj.setProperty(rt, "roses", "red"); + obj.setProperty(rt, "violets", "blue"); + Object oprop = Object(rt); + obj.setProperty(rt, "oprop", oprop); + obj.setProperty(rt, "aprop", Array(rt, 1)); + + EXPECT_TRUE(function("function (obj) { return " + "obj.roses == 'red' && " + "obj['violets'] == 'blue' && " + "typeof obj.oprop == 'object' && " + "Array.isArray(obj.aprop); }") + .call(rt, obj) + .getBool()); + + // Check that getPropertyNames doesn't return non-enumerable + // properties. + obj = function( + "function () {" + " obj = {};" + " obj.a = 1;" + " Object.defineProperty(obj, 'b', {" + " enumerable: false," + " value: 2" + " });" + " return obj;" + "}") + .call(rt) + .getObject(rt); + EXPECT_EQ(obj.getProperty(rt, "a").getNumber(), 1); + EXPECT_EQ(obj.getProperty(rt, "b").getNumber(), 2); + Array names = obj.getPropertyNames(rt); + EXPECT_EQ(names.size(rt), 1); + EXPECT_EQ(names.getValueAtIndex(rt, 0).getString(rt).utf8(rt), "a"); +} + +TEST_P(JSITest, HostObjectTest) { + class ConstantHostObject : public HostObject { + Value get(Runtime&, const PropNameID& sym) override { + return 9000; + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + + Object cho = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(function("function (obj) { return obj.someRandomProp == 9000; }") + .call(rt, cho) + .getBool()); + EXPECT_TRUE(cho.isHostObject(rt)); + EXPECT_TRUE(cho.getHostObject(rt).get() != nullptr); + + struct SameRuntimeHostObject : HostObject { + SameRuntimeHostObject(Runtime& rt) : rt_(rt){}; + + Value get(Runtime& rt, const PropNameID& sym) override { + EXPECT_EQ(&rt, &rt_); + return Value(); + } + + void set(Runtime& rt, const PropNameID& name, const Value& value) override { + EXPECT_EQ(&rt, &rt_); + } + + std::vector getPropertyNames(Runtime& rt) override { + EXPECT_EQ(&rt, &rt_); + return {}; + } + + Runtime& rt_; + }; + + Object srho = Object::createFromHostObject( + rt, std::make_shared(rt)); + // Test get's Runtime is as expected + function("function (obj) { return obj.isSame; }").call(rt, srho); + // ... and set + function("function (obj) { obj['k'] = 'v'; }").call(rt, srho); + // ... and getPropertyNames + function("function (obj) { for (k in obj) {} }").call(rt, srho); + + class TwiceHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + return String::createFromUtf8(rt, sym.utf8(rt) + sym.utf8(rt)); + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + + Object tho = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(function("function (obj) { return obj.abc == 'abcabc'; }") + .call(rt, tho) + .getBool()); + EXPECT_TRUE(function("function (obj) { return obj['def'] == 'defdef'; }") + .call(rt, tho) + .getBool()); + EXPECT_TRUE(function("function (obj) { return obj[12] === '1212'; }") + .call(rt, tho) + .getBool()); + EXPECT_TRUE(tho.isHostObject(rt)); + EXPECT_TRUE( + std::dynamic_pointer_cast(tho.getHostObject(rt)) == + nullptr); + EXPECT_TRUE(tho.getHostObject(rt).get() != nullptr); + + class PropNameIDHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + if (PropNameID::compare(rt, sym, PropNameID::forAscii(rt, "undef"))) { + return Value::undefined(); + } else { + return PropNameID::compare( + rt, sym, PropNameID::forAscii(rt, "somesymbol")); + } + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + + Object sho = Object::createFromHostObject( + rt, std::make_shared()); + EXPECT_TRUE(sho.isHostObject(rt)); + EXPECT_TRUE(function("function (obj) { return obj.undef; }") + .call(rt, sho) + .isUndefined()); + EXPECT_TRUE(function("function (obj) { return obj.somesymbol; }") + .call(rt, sho) + .getBool()); + EXPECT_FALSE(function("function (obj) { return obj.notsomuch; }") + .call(rt, sho) + .getBool()); + + class BagHostObject : public HostObject { + public: + const std::string& getThing() { + return bag_["thing"]; + } + + private: + Value get(Runtime& rt, const PropNameID& sym) override { + if (sym.utf8(rt) == "thing") { + return String::createFromUtf8(rt, bag_[sym.utf8(rt)]); + } + return Value::undefined(); + } + + void set(Runtime& rt, const PropNameID& sym, const Value& val) override { + std::string key(sym.utf8(rt)); + if (key == "thing") { + bag_[key] = val.toString(rt).utf8(rt); + } + } + + std::unordered_map bag_; + }; + + std::shared_ptr shbho = std::make_shared(); + Object bho = Object::createFromHostObject(rt, shbho); + EXPECT_TRUE(bho.isHostObject(rt)); + EXPECT_TRUE(function("function (obj) { return obj.undef; }") + .call(rt, bho) + .isUndefined()); + EXPECT_EQ( + function("function (obj) { obj.thing = 'hello'; return obj.thing; }") + .call(rt, bho) + .toString(rt) + .utf8(rt), + "hello"); + EXPECT_EQ(shbho->getThing(), "hello"); + + class ThrowingHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + throw std::runtime_error("Cannot get"); + } + + void set(Runtime& rt, const PropNameID& sym, const Value& val) override { + throw std::runtime_error("Cannot set"); + } + }; + + Object thro = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(thro.isHostObject(rt)); + std::string exc; + try { + function("function (obj) { return obj.thing; }").call(rt, thro); + } catch (const JSError& ex) { + exc = ex.what(); + } + EXPECT_NE(exc.find("Cannot get"), std::string::npos); + exc = ""; + try { + function("function (obj) { obj.thing = 'hello'; }").call(rt, thro); + } catch (const JSError& ex) { + exc = ex.what(); + } + EXPECT_NE(exc.find("Cannot set"), std::string::npos); + + class NopHostObject : public HostObject {}; + Object nopHo = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(nopHo.isHostObject(rt)); + EXPECT_TRUE(function("function (obj) { return obj.thing; }") + .call(rt, nopHo) + .isUndefined()); + + std::string nopExc; + try { + function("function (obj) { obj.thing = 'pika'; }").call(rt, nopHo); + } catch (const JSError& ex) { + nopExc = ex.what(); + } + EXPECT_NE(nopExc.find("TypeError: "), std::string::npos); + + class HostObjectWithPropertyNames : public HostObject { + std::vector getPropertyNames(Runtime& rt) override { + return PropNameID::names( + rt, "a_prop", "1", "false", "a_prop", "3", "c_prop"); + } + }; + + Object howpn = Object::createFromHostObject( + rt, std::make_shared()); + EXPECT_TRUE( + function( + "function (o) { return Object.getOwnPropertyNames(o).length == 5 }") + .call(rt, howpn) + .getBool()); + + auto hasOwnPropertyName = function( + "function (o, p) {" + " return Object.getOwnPropertyNames(o).indexOf(p) >= 0" + "}"); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "a_prop")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "1")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "false")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "3")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "c_prop")) + .getBool()); + EXPECT_FALSE(hasOwnPropertyName + .call(rt, howpn, String::createFromAscii(rt, "not_existing")) + .getBool()); +} + +TEST_P(JSITest, ArrayTest) { + eval("x = {1:2, '3':4, 5:'six', 'seven':['eight', 'nine']}"); + + Object x = rt.global().getPropertyAsObject(rt, "x"); + Array names = x.getPropertyNames(rt); + EXPECT_EQ(names.size(rt), 4); + std::unordered_set strNames; + for (size_t i = 0; i < names.size(rt); ++i) { + Value n = names.getValueAtIndex(rt, i); + EXPECT_TRUE(n.isString()); + strNames.insert(n.getString(rt).utf8(rt)); + } + + EXPECT_EQ(strNames.size(), 4); + EXPECT_EQ(strNames.count("1"), 1); + EXPECT_EQ(strNames.count("3"), 1); + EXPECT_EQ(strNames.count("5"), 1); + EXPECT_EQ(strNames.count("seven"), 1); + + Object seven = x.getPropertyAsObject(rt, "seven"); + Array arr = seven.getArray(rt); + + EXPECT_EQ(arr.size(rt), 2); + EXPECT_EQ(arr.getValueAtIndex(rt, 0).getString(rt).utf8(rt), "eight"); + EXPECT_EQ(arr.getValueAtIndex(rt, 1).getString(rt).utf8(rt), "nine"); + // TODO: test out of range + + EXPECT_EQ(x.getPropertyAsObject(rt, "seven").getArray(rt).size(rt), 2); + + // Check that property access with both symbols and strings can access + // array values. + EXPECT_EQ(seven.getProperty(rt, "0").getString(rt).utf8(rt), "eight"); + EXPECT_EQ(seven.getProperty(rt, "1").getString(rt).utf8(rt), "nine"); + seven.setProperty(rt, "1", "modified"); + EXPECT_EQ(seven.getProperty(rt, "1").getString(rt).utf8(rt), "modified"); + EXPECT_EQ(arr.getValueAtIndex(rt, 1).getString(rt).utf8(rt), "modified"); + EXPECT_EQ( + seven.getProperty(rt, PropNameID::forAscii(rt, "0")) + .getString(rt) + .utf8(rt), + "eight"); + seven.setProperty(rt, PropNameID::forAscii(rt, "0"), "modified2"); + EXPECT_EQ(arr.getValueAtIndex(rt, 0).getString(rt).utf8(rt), "modified2"); + + Array alpha = Array(rt, 4); + EXPECT_TRUE(alpha.getValueAtIndex(rt, 0).isUndefined()); + EXPECT_TRUE(alpha.getValueAtIndex(rt, 3).isUndefined()); + EXPECT_EQ(alpha.size(rt), 4); + alpha.setValueAtIndex(rt, 0, "a"); + alpha.setValueAtIndex(rt, 1, "b"); + EXPECT_EQ(alpha.length(rt), 4); + alpha.setValueAtIndex(rt, 2, "c"); + alpha.setValueAtIndex(rt, 3, "d"); + EXPECT_EQ(alpha.size(rt), 4); + + EXPECT_TRUE( + function( + "function (arr) { return " + "arr.length == 4 && " + "['a','b','c','d'].every(function(v,i) { return v === arr[i]}); }") + .call(rt, alpha) + .getBool()); + + Array alpha2 = Array(rt, 1); + alpha2 = std::move(alpha); + EXPECT_EQ(alpha2.size(rt), 4); +} + +TEST_P(JSITest, FunctionTest) { + // test move ctor + Function fmove = function("function() { return 1 }"); + { + Function g = function("function() { return 2 }"); + fmove = std::move(g); + } + EXPECT_EQ(fmove.call(rt).getNumber(), 2); + + // This tests all the function argument converters, and all the + // non-lvalue overloads of call(). + Function f = function( + "function(n, b, d, df, i, s1, s2, s3, o, a, f, v) { return " + "n === null && " + "b === true && " + "d === 3.14 && " + "Math.abs(df - 2.71) < 0.001 && " + "i === 17 && " + "s1 == 's1' && " + "s2 == 's2' && " + "s3 == 's3' && " + "typeof o == 'object' && " + "Array.isArray(a) && " + "typeof f == 'function' && " + "v == 42 }"); + std::string s3 = "s3"; + EXPECT_TRUE(f.call( + rt, + nullptr, + true, + 3.14, + 2.71f, + 17, + "s1", + String::createFromAscii(rt, "s2"), + s3, + Object(rt), + Array(rt, 1), + function("function(){}"), + Value(42)) + .getBool()); + + // lvalue overloads of call() + Function flv = function( + "function(s, o, a, f, v) { return " + "s == 's' && " + "typeof o == 'object' && " + "Array.isArray(a) && " + "typeof f == 'function' && " + "v == 42 }"); + + String s = String::createFromAscii(rt, "s"); + Object o = Object(rt); + Array a = Array(rt, 1); + Value v = 42; + EXPECT_TRUE(flv.call(rt, s, o, a, f, v).getBool()); + + Function f1 = function("function() { return 1; }"); + Function f2 = function("function() { return 2; }"); + f2 = std::move(f1); + EXPECT_EQ(f2.call(rt).getNumber(), 1); +} + +TEST_P(JSITest, FunctionThisTest) { + Function checkPropertyFunction = + function("function() { return this.a === 'a_property' }"); + + Object jsObject = Object(rt); + jsObject.setProperty(rt, "a", String::createFromUtf8(rt, "a_property")); + + class APropertyHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + return String::createFromUtf8(rt, "a_property"); + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + Object hostObject = + Object::createFromHostObject(rt, std::make_shared()); + + EXPECT_TRUE(checkPropertyFunction.callWithThis(rt, jsObject).getBool()); + EXPECT_TRUE(checkPropertyFunction.callWithThis(rt, hostObject).getBool()); + EXPECT_FALSE(checkPropertyFunction.callWithThis(rt, Array(rt, 5)).getBool()); + EXPECT_FALSE(checkPropertyFunction.call(rt).getBool()); +} + +TEST_P(JSITest, FunctionConstructorTest) { + Function ctor = function( + "function (a) {" + " if (typeof a !== 'undefined') {" + " this.pika = a;" + " }" + "}"); + ctor.getProperty(rt, "prototype") + .getObject(rt) + .setProperty(rt, "pika", "chu"); + auto empty = ctor.callAsConstructor(rt); + ASSERT_TRUE(empty.isObject()); + auto emptyObj = std::move(empty).getObject(rt); + EXPECT_EQ(emptyObj.getProperty(rt, "pika").getString(rt).utf8(rt), "chu"); + auto who = ctor.callAsConstructor(rt, "who"); + ASSERT_TRUE(who.isObject()); + auto whoObj = std::move(who).getObject(rt); + EXPECT_EQ(whoObj.getProperty(rt, "pika").getString(rt).utf8(rt), "who"); + + auto instanceof = function("function (o, b) { return o instanceof b; }"); + EXPECT_TRUE(instanceof.call(rt, emptyObj, ctor).getBool()); + EXPECT_TRUE(instanceof.call(rt, whoObj, ctor).getBool()); + + auto dateCtor = rt.global().getPropertyAsFunction(rt, "Date"); + auto date = dateCtor.callAsConstructor(rt); + EXPECT_TRUE(date.isObject()); + EXPECT_TRUE(instanceof.call(rt, date, dateCtor).getBool()); + // Sleep for 50 milliseconds + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + EXPECT_GE( + function("function (d) { return (new Date()).getTime() - d.getTime(); }") + .call(rt, date) + .getNumber(), + 50); +} + +TEST_P(JSITest, InstanceOfTest) { + auto ctor = function("function Rick() { this.say = 'wubalubadubdub'; }"); + auto newObj = function("function (ctor) { return new ctor(); }"); + auto instance = newObj.call(rt, ctor).getObject(rt); + EXPECT_TRUE(instance.instanceOf(rt, ctor)); + EXPECT_EQ( + instance.getProperty(rt, "say").getString(rt).utf8(rt), "wubalubadubdub"); + EXPECT_FALSE(Object(rt).instanceOf(rt, ctor)); + EXPECT_TRUE(ctor.callAsConstructor(rt, nullptr, 0) + .getObject(rt) + .instanceOf(rt, ctor)); +} + +TEST_P(JSITest, HostFunctionTest) { + auto one = std::make_shared(1); + Function plusOne = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "plusOne"), + 2, + [one, savedRt = &rt]( + Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + EXPECT_EQ(savedRt, &rt); + // We don't know if we're in strict mode or not, so it's either global + // or undefined. + EXPECT_TRUE( + Value::strictEquals(rt, thisVal, rt.global()) || + thisVal.isUndefined()); + return *one + args[0].getNumber() + args[1].getNumber(); + }); + + EXPECT_EQ(plusOne.call(rt, 1, 2).getNumber(), 4); + EXPECT_TRUE(checkValue(plusOne.call(rt, 3, 5), "9")); + rt.global().setProperty(rt, "plusOne", plusOne); + EXPECT_TRUE(eval("plusOne(20, 300) == 321").getBool()); + + Function dot = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "dot"), + 2, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + EXPECT_TRUE( + Value::strictEquals(rt, thisVal, rt.global()) || + thisVal.isUndefined()); + if (count != 2) { + throw std::runtime_error("expected 2 args"); + } + std::string ret = args[0].getString(rt).utf8(rt) + "." + + args[1].getString(rt).utf8(rt); + return String::createFromUtf8( + rt, reinterpret_cast(ret.data()), ret.size()); + }); + + rt.global().setProperty(rt, "cons", dot); + EXPECT_TRUE(eval("cons('left', 'right') == 'left.right'").getBool()); + EXPECT_TRUE(eval("cons.name == 'dot'").getBool()); + EXPECT_TRUE(eval("cons.length == 2").getBool()); + EXPECT_TRUE(eval("cons instanceof Function").getBool()); + + EXPECT_TRUE(eval("(function() {" + " try {" + " cons('fail'); return false;" + " } catch (e) {" + " return ((e instanceof Error) &&" + " (e.message == 'Exception in HostFunction: ' +" + " 'expected 2 args'));" + " }})()") + .getBool()); + + Function coolify = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "coolify"), + 0, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + EXPECT_EQ(count, 0); + std::string ret = thisVal.toString(rt).utf8(rt) + " is cool"; + return String::createFromUtf8( + rt, reinterpret_cast(ret.data()), ret.size()); + }); + rt.global().setProperty(rt, "coolify", coolify); + EXPECT_TRUE(eval("coolify.name == 'coolify'").getBool()); + EXPECT_TRUE(eval("coolify.length == 0").getBool()); + EXPECT_TRUE(eval("coolify.bind('R&M')() == 'R&M is cool'").getBool()); + EXPECT_TRUE(eval("(function() {" + " var s = coolify.bind(function(){})();" + " return s.lastIndexOf(' is cool') == (s.length - 8);" + "})()") + .getBool()); + + Function lookAtMe = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "lookAtMe"), + 0, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) + -> Value { + EXPECT_TRUE(thisVal.isObject()); + EXPECT_EQ( + thisVal.getObject(rt) + .getProperty(rt, "name") + .getString(rt) + .utf8(rt), + "mr.meeseeks"); + return Value(); + }); + rt.global().setProperty(rt, "lookAtMe", lookAtMe); + EXPECT_TRUE(eval("lookAtMe.bind({'name': 'mr.meeseeks'})()").isUndefined()); + + struct Callable { + Callable(std::string s) : str(s) {} + + Value + operator()(Runtime& rt, const Value&, const Value* args, size_t count) { + if (count != 1) { + return Value(); + } + return String::createFromUtf8( + rt, args[0].toString(rt).utf8(rt) + " was called with " + str); + } + + std::string str; + }; + + Function callable = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "callable"), + 1, + Callable("std::function::target")); + EXPECT_EQ( + function("function (f) { return f('A cat'); }") + .call(rt, callable) + .getString(rt) + .utf8(rt), + "A cat was called with std::function::target"); + EXPECT_TRUE(callable.isHostFunction(rt)); + EXPECT_NE(callable.getHostFunction(rt).target(), nullptr); + + std::string strval = "strval1"; + auto getter = Object(rt); + getter.setProperty( + rt, + "get", + Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "getter"), + 1, + [&strval]( + Runtime& rt, + const Value& thisVal, + const Value* args, + size_t count) -> Value { + return String::createFromUtf8(rt, strval); + })); + auto obj = Object(rt); + rt.global() + .getPropertyAsObject(rt, "Object") + .getPropertyAsFunction(rt, "defineProperty") + .call(rt, obj, "prop", getter); + EXPECT_TRUE(function("function(value) { return value.prop == 'strval1'; }") + .call(rt, obj) + .getBool()); + strval = "strval2"; + EXPECT_TRUE(function("function(value) { return value.prop == 'strval2'; }") + .call(rt, obj) + .getBool()); +} + +TEST_P(JSITest, ValueTest) { + EXPECT_TRUE(checkValue(Value::undefined(), "undefined")); + EXPECT_TRUE(checkValue(Value(), "undefined")); + EXPECT_TRUE(checkValue(Value::null(), "null")); + EXPECT_TRUE(checkValue(nullptr, "null")); + + EXPECT_TRUE(checkValue(Value(false), "false")); + EXPECT_TRUE(checkValue(false, "false")); + EXPECT_TRUE(checkValue(true, "true")); + + EXPECT_TRUE(checkValue(Value(1.5), "1.5")); + EXPECT_TRUE(checkValue(2.5, "2.5")); + + EXPECT_TRUE(checkValue(Value(10), "10")); + EXPECT_TRUE(checkValue(20, "20")); + EXPECT_TRUE(checkValue(30, "30")); + + // rvalue implicit conversion + EXPECT_TRUE(checkValue(String::createFromAscii(rt, "one"), "'one'")); + // lvalue explicit copy + String s = String::createFromAscii(rt, "two"); + EXPECT_TRUE(checkValue(Value(rt, s), "'two'")); + + { + // rvalue assignment of trivial value + Value v1 = 100; + Value v2 = String::createFromAscii(rt, "hundred"); + v2 = std::move(v1); + EXPECT_TRUE(v2.isNumber()); + EXPECT_EQ(v2.getNumber(), 100); + } + + { + // rvalue assignment of js heap value + Value v1 = String::createFromAscii(rt, "hundred"); + Value v2 = 100; + v2 = std::move(v1); + EXPECT_TRUE(v2.isString()); + EXPECT_EQ(v2.getString(rt).utf8(rt), "hundred"); + } + + Object o = Object(rt); + EXPECT_TRUE(function("function(value) { return typeof(value) == 'object'; }") + .call(rt, Value(rt, o)) + .getBool()); + + uint8_t utf8[] = "[null, 2, \"c\", \"emoji: \xf0\x9f\x86\x97\", {}]"; + + EXPECT_TRUE( + function("function (arr) { return " + "Array.isArray(arr) && " + "arr.length == 5 && " + "arr[0] === null && " + "arr[1] == 2 && " + "arr[2] == 'c' && " + "arr[3] == 'emoji: \\uD83C\\uDD97' && " + "typeof arr[4] == 'object'; }") + .call(rt, Value::createFromJsonUtf8(rt, utf8, sizeof(utf8) - 1)) + .getBool()); + + EXPECT_TRUE(eval("undefined").isUndefined()); + EXPECT_TRUE(eval("null").isNull()); + EXPECT_TRUE(eval("true").isBool()); + EXPECT_TRUE(eval("false").isBool()); + EXPECT_TRUE(eval("123").isNumber()); + EXPECT_TRUE(eval("123.4").isNumber()); + EXPECT_TRUE(eval("'str'").isString()); + // "{}" returns undefined. empty code block? + EXPECT_TRUE(eval("({})").isObject()); + EXPECT_TRUE(eval("[]").isObject()); + EXPECT_TRUE(eval("(function(){})").isObject()); + + EXPECT_EQ(eval("123").getNumber(), 123); + EXPECT_EQ(eval("123.4").getNumber(), 123.4); + EXPECT_EQ(eval("'str'").getString(rt).utf8(rt), "str"); + EXPECT_TRUE(eval("[]").getObject(rt).isArray(rt)); + + EXPECT_EQ(eval("456").asNumber(), 456); + EXPECT_THROW(eval("'word'").asNumber(), JSIException); + EXPECT_EQ( + eval("({1:2, 3:4})").asObject(rt).getProperty(rt, "1").getNumber(), 2); + EXPECT_THROW(eval("'oops'").asObject(rt), JSIException); + + EXPECT_EQ(eval("['zero',1,2,3]").toString(rt).utf8(rt), "zero,1,2,3"); +} + +TEST_P(JSITest, EqualsTest) { + EXPECT_TRUE(Object::strictEquals(rt, rt.global(), rt.global())); + EXPECT_TRUE(Value::strictEquals(rt, 1, 1)); + EXPECT_FALSE(Value::strictEquals(rt, true, 1)); + EXPECT_FALSE(Value::strictEquals(rt, true, false)); + EXPECT_TRUE(Value::strictEquals(rt, false, false)); + EXPECT_FALSE(Value::strictEquals(rt, nullptr, 1)); + EXPECT_TRUE(Value::strictEquals(rt, nullptr, nullptr)); + EXPECT_TRUE(Value::strictEquals(rt, Value::undefined(), Value())); + EXPECT_TRUE(Value::strictEquals(rt, rt.global(), Value(rt.global()))); + EXPECT_FALSE(Value::strictEquals( + rt, + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN())); + EXPECT_FALSE(Value::strictEquals( + rt, + std::numeric_limits::signaling_NaN(), + std::numeric_limits::signaling_NaN())); + EXPECT_TRUE(Value::strictEquals(rt, +0.0, -0.0)); + EXPECT_TRUE(Value::strictEquals(rt, -0.0, +0.0)); + + Function noop = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "noop"), + 0, + [](const Runtime&, const Value&, const Value*, size_t) { + return Value(); + }); + auto noopDup = Value(rt, noop).getObject(rt); + EXPECT_TRUE(Object::strictEquals(rt, noop, noopDup)); + EXPECT_TRUE(Object::strictEquals(rt, noopDup, noop)); + EXPECT_FALSE(Object::strictEquals(rt, noop, rt.global())); + EXPECT_TRUE(Object::strictEquals(rt, noop, noop)); + EXPECT_TRUE(Value::strictEquals(rt, Value(rt, noop), Value(rt, noop))); + + String str = String::createFromAscii(rt, "rick"); + String strDup = String::createFromAscii(rt, "rick"); + String otherStr = String::createFromAscii(rt, "morty"); + EXPECT_TRUE(String::strictEquals(rt, str, str)); + EXPECT_TRUE(String::strictEquals(rt, str, strDup)); + EXPECT_TRUE(String::strictEquals(rt, strDup, str)); + EXPECT_FALSE(String::strictEquals(rt, str, otherStr)); + EXPECT_TRUE(Value::strictEquals(rt, Value(rt, str), Value(rt, str))); + EXPECT_FALSE(Value::strictEquals(rt, Value(rt, str), Value(rt, noop))); + EXPECT_FALSE(Value::strictEquals(rt, Value(rt, str), 1.0)); +} + +TEST_P(JSITest, ExceptionStackTraceTest) { + static const char invokeUndefinedScript[] = + "function hello() {" + " var a = {}; a.log(); }" + "function world() { hello(); }" + "world()"; + std::string stack; + try { + rt.evaluateJavaScript( + std::make_unique(invokeUndefinedScript), ""); + } catch (JSError& e) { + stack = e.getStack(); + } + EXPECT_NE(stack.find("world"), std::string::npos); +} + +TEST_P(JSITest, PreparedJavaScriptSourceTest) { + rt.evaluateJavaScript(std::make_unique("var q = 0;"), ""); + auto prep = rt.prepareJavaScript(std::make_unique("q++;"), ""); + EXPECT_EQ(rt.global().getProperty(rt, "q").getNumber(), 0); + rt.evaluatePreparedJavaScript(prep); + EXPECT_EQ(rt.global().getProperty(rt, "q").getNumber(), 1); + rt.evaluatePreparedJavaScript(prep); + EXPECT_EQ(rt.global().getProperty(rt, "q").getNumber(), 2); +} + +TEST_P(JSITest, PreparedJavaScriptURLInBacktrace) { + std::string sourceURL = "//PreparedJavaScriptURLInBacktrace/Test/URL"; + std::string throwingSource = + "function thrower() { throw new Error('oops')}" + "thrower();"; + auto prep = rt.prepareJavaScript( + std::make_unique(throwingSource), sourceURL); + try { + rt.evaluatePreparedJavaScript(prep); + FAIL() << "prepareJavaScript should have thrown an exception"; + } catch (facebook::jsi::JSError err) { + EXPECT_NE(std::string::npos, err.getStack().find(sourceURL)) + << "Backtrace should contain source URL"; + } +} + +namespace { + +unsigned countOccurences(const std::string& of, const std::string& in) { + unsigned occurences = 0; + std::string::size_type lastOccurence = -1; + while ((lastOccurence = in.find(of, lastOccurence + 1)) != + std::string::npos) { + occurences++; + } + return occurences; +} + +} // namespace + +TEST_P(JSITest, JSErrorsArePropagatedNicely) { + unsigned callsBeoreError = 5; + + Function sometimesThrows = function( + "function sometimesThrows(shouldThrow, callback) {" + " if (shouldThrow) {" + " throw Error('Omg, what a nasty exception')" + " }" + " callback(callback);" + "}"); + + Function callback = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "callback"), + 0, + [&sometimesThrows, &callsBeoreError]( + Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + return sometimesThrows.call(rt, --callsBeoreError == 0, args[0]); + }); + + try { + sometimesThrows.call(rt, false, callback); + } catch (JSError& error) { + EXPECT_EQ(error.getMessage(), "Omg, what a nasty exception"); + EXPECT_EQ(countOccurences("sometimesThrows", error.getStack()), 6); + + // system JSC JSI does not implement host function names + // EXPECT_EQ(countOccurences("callback", error.getStack(rt)), 5); + } +} + +TEST_P(JSITest, JSErrorsCanBeConstructedWithStack) { + auto err = JSError(rt, "message", "stack"); + EXPECT_EQ(err.getMessage(), "message"); + EXPECT_EQ(err.getStack(), "stack"); +} + +TEST_P(JSITest, ScopeDoesNotCrashTest) { + Scope scope(rt); + Object o(rt); +} + +TEST_P(JSITest, ScopeDoesNotCrashWhenValueEscapes) { + Value v; + Scope::callInNewScope(rt, [&]() { + Object o(rt); + o.setProperty(rt, "a", 5); + v = std::move(o); + }); + EXPECT_EQ(v.getObject(rt).getProperty(rt, "a").getNumber(), 5); +} + +// Verifies you can have a host object that emulates a normal object +TEST_P(JSITest, HostObjectWithValueMembers) { + class Bag : public HostObject { + public: + Bag() = default; + + const Value& operator[](const std::string& name) const { + auto iter = data_.find(name); + if (iter == data_.end()) { + return undef_; + } + return iter->second; + } + + protected: + Value get(Runtime& rt, const PropNameID& name) override { + return Value(rt, (*this)[name.utf8(rt)]); + } + + void set(Runtime& rt, const PropNameID& name, const Value& val) override { + data_.emplace(name.utf8(rt), Value(rt, val)); + } + + Value undef_; + std::map data_; + }; + + auto sharedBag = std::make_shared(); + auto& bag = *sharedBag; + Object jsbag = Object::createFromHostObject(rt, std::move(sharedBag)); + auto set = function( + "function (o) {" + " o.foo = 'bar';" + " o.count = 37;" + " o.nul = null;" + " o.iscool = true;" + " o.obj = { 'foo': 'bar' };" + "}"); + set.call(rt, jsbag); + auto checkFoo = function("function (o) { return o.foo === 'bar'; }"); + auto checkCount = function("function (o) { return o.count === 37; }"); + auto checkNul = function("function (o) { return o.nul === null; }"); + auto checkIsCool = function("function (o) { return o.iscool === true; }"); + auto checkObj = function( + "function (o) {" + " return (typeof o.obj) === 'object' && o.obj.foo === 'bar';" + "}"); + // Check this looks good from js + EXPECT_TRUE(checkFoo.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkCount.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkNul.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkIsCool.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkObj.call(rt, jsbag).getBool()); + + // Check this looks good from c++ + EXPECT_EQ(bag["foo"].getString(rt).utf8(rt), "bar"); + EXPECT_EQ(bag["count"].getNumber(), 37); + EXPECT_TRUE(bag["nul"].isNull()); + EXPECT_TRUE(bag["iscool"].getBool()); + EXPECT_EQ( + bag["obj"].getObject(rt).getProperty(rt, "foo").getString(rt).utf8(rt), + "bar"); +} + +TEST_P(JSITest, DecoratorTest) { + struct Count { + // init here is just to show that a With type does not need to be + // default constructible. + explicit Count(int init) : count(init) {} + + // Test optional before method. + + void after() { + ++count; + } + + int count; + }; + + static constexpr int kInit = 17; + + class CountRuntime final : public WithRuntimeDecorator { + public: + explicit CountRuntime(std::unique_ptr rt) + : WithRuntimeDecorator(*rt, count_), + rt_(std::move(rt)), + count_(kInit) {} + + int count() { + return count_.count; + } + + private: + std::unique_ptr rt_; + Count count_; + }; + + CountRuntime crt(factory()); + + crt.description(); + EXPECT_EQ(crt.count(), kInit + 1); + + crt.global().setProperty(crt, "o", Object(crt)); + EXPECT_EQ(crt.count(), kInit + 6); +} + +TEST_P(JSITest, MultiDecoratorTest) { + struct Inc { + void before() { + ++count; + } + + // Test optional after method. + + int count = 0; + }; + + struct Nest { + void before() { + ++nest; + } + + void after() { + --nest; + } + + int nest = 0; + }; + + class MultiRuntime final : public WithRuntimeDecorator> { + public: + explicit MultiRuntime(std::unique_ptr rt) + : WithRuntimeDecorator>(*rt, tuple_), + rt_(std::move(rt)) {} + + int count() { + return std::get<0>(tuple_).count; + } + int nest() { + return std::get<1>(tuple_).nest; + } + + private: + std::unique_ptr rt_; + WithTuple tuple_; + }; + + MultiRuntime mrt(factory()); + + Function expectNestOne = Function::createFromHostFunction( + mrt, + PropNameID::forAscii(mrt, "expectNestOne"), + 0, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + MultiRuntime* funcmrt = dynamic_cast(&rt); + EXPECT_NE(funcmrt, nullptr); + EXPECT_EQ(funcmrt->count(), 3); + EXPECT_EQ(funcmrt->nest(), 1); + return Value::undefined(); + }); + + expectNestOne.call(mrt); + + EXPECT_EQ(mrt.count(), 3); + EXPECT_EQ(mrt.nest(), 0); +} + +TEST_P(JSITest, SymbolTest) { + if (!rt.global().hasProperty(rt, "Symbol")) { + // Symbol is an es6 feature which doesn't exist in older VMs. So + // the tests which might be elsewhere are all here so they can be + // skipped. + return; + } + + // ObjectTest + eval("x = {1:2, 'three':Symbol('four')}"); + Object x = rt.global().getPropertyAsObject(rt, "x"); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 2); + EXPECT_TRUE(x.hasProperty(rt, "three")); + EXPECT_EQ( + x.getProperty(rt, "three").getSymbol(rt).toString(rt), "Symbol(four)"); + + // ValueTest + EXPECT_TRUE(eval("Symbol('sym')").isSymbol()); + EXPECT_EQ(eval("Symbol('sym')").getSymbol(rt).toString(rt), "Symbol(sym)"); + + // EqualsTest + EXPECT_FALSE(Symbol::strictEquals( + rt, + eval("Symbol('a')").getSymbol(rt), + eval("Symbol('a')").getSymbol(rt))); + EXPECT_TRUE(Symbol::strictEquals( + rt, + eval("Symbol.for('a')").getSymbol(rt), + eval("Symbol.for('a')").getSymbol(rt))); + EXPECT_FALSE( + Value::strictEquals(rt, eval("Symbol('a')"), eval("Symbol('a')"))); + EXPECT_TRUE(Value::strictEquals( + rt, eval("Symbol.for('a')"), eval("Symbol.for('a')"))); + EXPECT_FALSE(Value::strictEquals(rt, eval("Symbol('a')"), eval("'a'"))); +} + +INSTANTIATE_TEST_CASE_P( + Runtimes, + JSITest, + ::testing::ValuesIn(runtimeGenerators())); diff --git a/ReactCommon/jsi/jsi/test/testlib.h b/ReactCommon/jsi/jsi/test/testlib.h new file mode 100644 index 00000000000000..604fc044d6f773 --- /dev/null +++ b/ReactCommon/jsi/jsi/test/testlib.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +#pragma once + +#include +#include +#include + +#include +#include + +namespace facebook { +namespace jsi { + +class Runtime; + +using RuntimeFactory = std::function()>; + +std::vector runtimeGenerators(); + +class JSITestBase : public ::testing::TestWithParam { + public: + JSITestBase() : factory(GetParam()), runtime(factory()), rt(*runtime) {} + + Value eval(const char* code) { + return rt.global().getPropertyAsFunction(rt, "eval").call(rt, code); + } + + Function function(const std::string& code) { + return eval(("(" + code + ")").c_str()).getObject(rt).getFunction(rt); + } + + bool checkValue(const Value& value, const std::string& jsValue) { + return function("function(value) { return value == " + jsValue + "; }") + .call(rt, std::move(value)) + .getBool(); + } + + RuntimeFactory factory; + std::unique_ptr runtime; + Runtime& rt; +}; +} // namespace jsi +} // namespace facebook From 15302284cc4d1840e9003ab781626c156d3691aa Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 4 Jun 2019 15:28:24 -0700 Subject: [PATCH 095/330] Fabric: Enable CXX (aka Default) platfrom fravour for all C++ Fabric targets Summary: First of all, seems it's the right thing to do. Fabric C++ code is cross-platfrom and should run on *all* platforms including Windows, Linux, and Mac. While we don't have a real *production* use cases where we need compilation for desktops, having CXX target is really handy for two reasons: * It simplifies local test running process. Instead of going to `/fbandroid/` and executing something like `buck test fbsource//xplat/js/react-native-github/ReactCommon/fabric/core:coreAndroid` (note the suffix). We can just do `buck test fbsource//xplat/js/react-native-github/ReactCommon/fabric/core:core` everywhere and it works now out of the box. Running tests with "Apple" flavor never worked for me. * It allows creating synthetic benchmark tests (using Google Benchmark) that can be used as a rough approximation of code micro-optimizations. Reviewed By: JoshuaGross Differential Revision: D15608678 fbshipit-source-id: d2449035685dbca6ab983480f5334ec4ac11cd35 --- ReactCommon/better/BUCK | 3 +- ReactCommon/config/BUCK | 4 +- ReactCommon/fabric/attributedstring/BUCK | 5 +- .../fabric/components/activityindicator/BUCK | 17 ++++-- ReactCommon/fabric/components/image/BUCK | 5 +- ReactCommon/fabric/components/modal/BUCK | 9 ++-- ReactCommon/fabric/components/root/BUCK | 5 +- ReactCommon/fabric/components/scrollview/BUCK | 5 +- ReactCommon/fabric/components/slider/BUCK | 13 +++-- ReactCommon/fabric/components/text/BUCK | 15 ++++-- ReactCommon/fabric/components/view/BUCK | 5 +- ReactCommon/fabric/core/BUCK | 17 ++++-- ReactCommon/fabric/debug/BUCK | 5 +- ReactCommon/fabric/graphics/BUCK | 20 +++++-- .../platform/{android => cxx}/Color.cpp | 0 .../platform/{android => cxx}/Color.h | 0 .../platform/{android => cxx}/Float.h | 0 ReactCommon/fabric/imagemanager/BUCK | 10 ++-- .../{android => cxx}/ImageManager.cpp | 0 .../{android => cxx}/ImageRequest.cpp | 0 ReactCommon/fabric/mounting/BUCK | 5 +- ReactCommon/fabric/textlayoutmanager/BUCK | 42 ++++++++++----- .../platform/cxx/TextLayoutManager.cpp | 27 ++++++++++ .../platform/cxx/TextLayoutManager.h | 54 +++++++++++++++++++ ReactCommon/fabric/uimanager/BUCK | 5 +- ReactCommon/utils/BUCK | 4 +- packages/react-native-codegen/DEFS.bzl | 5 +- 27 files changed, 216 insertions(+), 64 deletions(-) rename ReactCommon/fabric/graphics/platform/{android => cxx}/Color.cpp (100%) rename ReactCommon/fabric/graphics/platform/{android => cxx}/Color.h (100%) rename ReactCommon/fabric/graphics/platform/{android => cxx}/Float.h (100%) rename ReactCommon/fabric/imagemanager/platform/{android => cxx}/ImageManager.cpp (100%) rename ReactCommon/fabric/imagemanager/platform/{android => cxx}/ImageRequest.cpp (100%) create mode 100644 ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp create mode 100644 ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h diff --git a/ReactCommon/better/BUCK b/ReactCommon/better/BUCK index d59c2672394a93..8708525242bdbe 100644 --- a/ReactCommon/better/BUCK +++ b/ReactCommon/better/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "get_apple_compiler_flags", "get_apple_inspector_flags", "rn_xplat_cxx_library", @@ -38,7 +39,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/config/BUCK b/ReactCommon/config/BUCK index 85ad4e3edae348..2e74ef11533ec5 100644 --- a/ReactCommon/config/BUCK +++ b/ReactCommon/config/BUCK @@ -1,4 +1,4 @@ -load("@fbsource//tools/build_defs:default_platform_defs.bzl", "ANDROID", "APPLE") +load("@fbsource//tools/build_defs:default_platform_defs.bzl", "ANDROID", "APPLE", "CXX") load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob") load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "flags", "get_debug_preprocessor_flags", "get_static_library_ios_flags") load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "get_apple_inspector_flags", "rn_xplat_cxx_library") @@ -27,7 +27,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/fabric/attributedstring/BUCK b/ReactCommon/fabric/attributedstring/BUCK index a0f0b3bfb08075..58b66dd2f0fc27 100644 --- a/ReactCommon/fabric/attributedstring/BUCK +++ b/ReactCommon/fabric/attributedstring/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,7 +41,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -72,7 +73,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/activityindicator/BUCK b/ReactCommon/fabric/components/activityindicator/BUCK index a1440b1a49846f..17866577999176 100644 --- a/ReactCommon/fabric/components/activityindicator/BUCK +++ b/ReactCommon/fabric/components/activityindicator/BUCK @@ -1,5 +1,16 @@ load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob") +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "APPLE", + "CXX", + "fb_xplat_cxx_test", + "get_apple_compiler_flags", + "get_apple_inspector_flags", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) APPLE_COMPILER_FLAGS = get_apple_compiler_flags() @@ -26,7 +37,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -57,7 +68,7 @@ fb_xplat_cxx_test( "-std=c++14", "-Wall", ], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/image/BUCK b/ReactCommon/fabric/components/image/BUCK index 8416205ae70fae..539fde772bf316 100644 --- a/ReactCommon/fabric/components/image/BUCK +++ b/ReactCommon/fabric/components/image/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -36,7 +37,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -69,7 +70,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/modal/BUCK b/ReactCommon/fabric/components/modal/BUCK index 94272fdfecb815..a8c0314f87c62c 100644 --- a/ReactCommon/fabric/components/modal/BUCK +++ b/ReactCommon/fabric/components/modal/BUCK @@ -3,10 +3,10 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", - "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob", @@ -37,9 +37,6 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], - fbandroid_deps = [ - react_native_target("jni/react/jni:jni"), - ], fbandroid_exported_headers = subdir_glob( [ ("", "*.h"), @@ -64,7 +61,7 @@ rn_xplat_cxx_library( prefix = "react/components/modal", ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -100,7 +97,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/root/BUCK b/ReactCommon/fabric/components/root/BUCK index 54cd52e105a233..2992818afbe5f9 100644 --- a/ReactCommon/fabric/components/root/BUCK +++ b/ReactCommon/fabric/components/root/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -36,7 +37,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -69,7 +70,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/scrollview/BUCK b/ReactCommon/fabric/components/scrollview/BUCK index 8337ba6299a974..6346d835303759 100644 --- a/ReactCommon/fabric/components/scrollview/BUCK +++ b/ReactCommon/fabric/components/scrollview/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,7 +41,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -72,7 +73,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/slider/BUCK b/ReactCommon/fabric/components/slider/BUCK index 4209dd66678bf3..a22ccb5f29d121 100644 --- a/ReactCommon/fabric/components/slider/BUCK +++ b/ReactCommon/fabric/components/slider/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -37,6 +38,7 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_tests = [":tests"], fbandroid_deps = [ react_native_target("jni/react/jni:jni"), ], @@ -69,13 +71,11 @@ rn_xplat_cxx_library( ios_srcs = glob( ["platform/ios/*.cpp"], ), - macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [":tests"], visibility = ["PUBLIC"], deps = [ "fbsource//xplat/fbsystrace:fbsystrace", @@ -106,7 +106,12 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = ( + # `Apple` and `Android` flavors are disabled because the module (built with those flavors) requires Emulator/Simulator (which is expensive and slow). At the same time, we don't really have tests here. + # ANDROID, + # APPLE, + CXX, + ), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/text/BUCK b/ReactCommon/fabric/components/text/BUCK index b47afbb67b6461..a74a1e3dda3fe7 100644 --- a/ReactCommon/fabric/components/text/BUCK +++ b/ReactCommon/fabric/components/text/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,16 +41,15 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_tests = [":tests"], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, - macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [":tests"], visibility = ["PUBLIC"], deps = [ "fbsource//xplat/fbsystrace:fbsystrace", @@ -81,7 +81,14 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = ( + # `Apple` and `Android` flavors are disabled because the module depends on `textlayoutmanager` which requires real an Emulator/Simulator to run. + # At the same time, the code of tests does not rely on the simulator capabilities and it would be wasteful to add `fbandroid_use_instrumentation_test = True`. + # (Beware of this option though.) + # ANDROID, + # APPLE, + CXX + ), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/view/BUCK b/ReactCommon/fabric/components/view/BUCK index f7edaa58ea33ca..998866eacc8b97 100644 --- a/ReactCommon/fabric/components/view/BUCK +++ b/ReactCommon/fabric/components/view/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -43,7 +44,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -75,7 +76,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index 27456f16061242..e10813059a83a9 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -1,5 +1,16 @@ load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob") +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "APPLE", + "CXX", + "fb_xplat_cxx_test", + "get_apple_compiler_flags", + "get_apple_inspector_flags", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) APPLE_COMPILER_FLAGS = get_apple_compiler_flags() @@ -36,7 +47,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -68,7 +79,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index 3a368828e6ce0a..31330eb81db722 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -1,3 +1,4 @@ +load("@fbsource//tools/build_defs:default_platform_defs.bzl", "CXX") load( "@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags", @@ -42,7 +43,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -68,7 +69,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/graphics/BUCK b/ReactCommon/fabric/graphics/BUCK index 2a884519a33f80..611056a1bbdeb0 100644 --- a/ReactCommon/fabric/graphics/BUCK +++ b/ReactCommon/fabric/graphics/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -38,15 +39,26 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_exported_headers = subdir_glob( + [ + ("platform/cxx", "**/*.h"), + ], + prefix = "react/graphics", + ), + cxx_srcs = glob( + [ + "platform/cxx/**/*.cpp", + ], + ), fbandroid_exported_headers = subdir_glob( [ - ("platform/android", "**/*.h"), + ("platform/cxx", "**/*.h"), ], prefix = "react/graphics", ), fbandroid_srcs = glob( [ - "platform/android/**/*.cpp", + "platform/cxx/**/*.cpp", ], ), fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, @@ -74,7 +86,7 @@ rn_xplat_cxx_library( ], ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -101,7 +113,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/graphics/platform/android/Color.cpp b/ReactCommon/fabric/graphics/platform/cxx/Color.cpp similarity index 100% rename from ReactCommon/fabric/graphics/platform/android/Color.cpp rename to ReactCommon/fabric/graphics/platform/cxx/Color.cpp diff --git a/ReactCommon/fabric/graphics/platform/android/Color.h b/ReactCommon/fabric/graphics/platform/cxx/Color.h similarity index 100% rename from ReactCommon/fabric/graphics/platform/android/Color.h rename to ReactCommon/fabric/graphics/platform/cxx/Color.h diff --git a/ReactCommon/fabric/graphics/platform/android/Float.h b/ReactCommon/fabric/graphics/platform/cxx/Float.h similarity index 100% rename from ReactCommon/fabric/graphics/platform/android/Float.h rename to ReactCommon/fabric/graphics/platform/cxx/Float.h diff --git a/ReactCommon/fabric/imagemanager/BUCK b/ReactCommon/fabric/imagemanager/BUCK index d1014ecbc74f9c..c8de61999d844c 100644 --- a/ReactCommon/fabric/imagemanager/BUCK +++ b/ReactCommon/fabric/imagemanager/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -31,19 +32,20 @@ rn_xplat_cxx_library( fbandroid_exported_headers = subdir_glob( [ ("", "*.h"), + ("platform/cxx", "**/*.h"), ], prefix = "react/imagemanager", ), fbandroid_headers = subdir_glob( [ ("", "*.h"), - ("platform/android", "**/*.h"), + ("platform/cxx", "**/*.h"), ], prefix = "", ), fbandroid_srcs = glob( [ - "platform/android/**/*.cpp", + "platform/cxx/**/*.cpp", ], ), fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, @@ -82,7 +84,7 @@ rn_xplat_cxx_library( ], ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -114,7 +116,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/imagemanager/platform/android/ImageManager.cpp b/ReactCommon/fabric/imagemanager/platform/cxx/ImageManager.cpp similarity index 100% rename from ReactCommon/fabric/imagemanager/platform/android/ImageManager.cpp rename to ReactCommon/fabric/imagemanager/platform/cxx/ImageManager.cpp diff --git a/ReactCommon/fabric/imagemanager/platform/android/ImageRequest.cpp b/ReactCommon/fabric/imagemanager/platform/cxx/ImageRequest.cpp similarity index 100% rename from ReactCommon/fabric/imagemanager/platform/android/ImageRequest.cpp rename to ReactCommon/fabric/imagemanager/platform/cxx/ImageRequest.cpp diff --git a/ReactCommon/fabric/mounting/BUCK b/ReactCommon/fabric/mounting/BUCK index 268c698fb424bc..c4c9ec908705af 100644 --- a/ReactCommon/fabric/mounting/BUCK +++ b/ReactCommon/fabric/mounting/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -41,7 +42,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -75,7 +76,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/textlayoutmanager/BUCK b/ReactCommon/fabric/textlayoutmanager/BUCK index f5dbeffe240ca9..8ecdacd51f0051 100644 --- a/ReactCommon/fabric/textlayoutmanager/BUCK +++ b/ReactCommon/fabric/textlayoutmanager/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -17,21 +18,15 @@ APPLE_COMPILER_FLAGS = get_apple_compiler_flags() rn_xplat_cxx_library( name = "textlayoutmanager", srcs = glob( - [ - "*.cpp", - ], + [], ), headers = subdir_glob( - [ - ("", "*.h"), - ], + [], prefix = "", ), header_namespace = "", exported_headers = subdir_glob( - [ - ("", "*.h"), - ], + [], prefix = "react/textlayoutmanager", ), compiler_flags = [ @@ -40,12 +35,29 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_exported_headers = subdir_glob( + [ + ("platform/cxx", "*.h"), + ], + prefix = "react/textlayoutmanager", + ), + cxx_headers = subdir_glob( + [ + ("platform/cxx", "**/*.h"), + ], + prefix = "", + ), + cxx_srcs = glob( + [ + "platform/cxx/**/*.cpp", + ], + ), + cxx_tests = [":tests"], fbandroid_deps = [ react_native_target("jni/react/jni:jni"), ], fbandroid_exported_headers = subdir_glob( [ - ("", "*.h"), ("platform/android", "*.h"), ], prefix = "react/textlayoutmanager", @@ -90,12 +102,11 @@ rn_xplat_cxx_library( ], ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [":tests"], visibility = ["PUBLIC"], deps = [ "fbsource//xplat/fbsystrace:fbsystrace", @@ -123,7 +134,12 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = ( + # `Apple` and `Android` flavors are disabled because the module (built with those flavors) requires Emulator/Simulator (which is expensive and slow). At the same time, we don't really have tests here. + # ANDROID, + # APPLE, + CXX, + ), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp new file mode 100644 index 00000000000000..a3e9cb1eb9666a --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TextLayoutManager.h" + +namespace facebook { +namespace react { + +TextLayoutManager::~TextLayoutManager() {} + +void *TextLayoutManager::getNativeTextLayoutManager() const { + return self_; +} + +Size TextLayoutManager::measure( + AttributedString attributedString, + ParagraphAttributes paragraphAttributes, + LayoutConstraints layoutConstraints) const { + return Size{0, 0}; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h new file mode 100644 index 00000000000000..6bc496ba2044c8 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class TextLayoutManager; + +using SharedTextLayoutManager = std::shared_ptr; + +/* + * Cross platform facade for Android-specific TextLayoutManager. + */ +class TextLayoutManager { + public: + TextLayoutManager(const ContextContainer::Shared &contextContainer) + : contextContainer_(contextContainer){}; + ~TextLayoutManager(); + + /* + * Measures `attributedString` using native text rendering infrastructure. + */ + Size measure( + AttributedString attributedString, + ParagraphAttributes paragraphAttributes, + LayoutConstraints layoutConstraints) const; + + /* + * Returns an opaque pointer to platform-specific TextLayoutManager. + * Is used on a native views layer to delegate text rendering to the manager. + */ + void *getNativeTextLayoutManager() const; + + private: + void *self_; + + ContextContainer::Shared contextContainer_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index a04c71a6923e25..4a4cabbedc1689 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,7 +41,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -76,7 +77,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/utils/BUCK b/ReactCommon/utils/BUCK index dd317a18e7026e..c582782dfa18a3 100644 --- a/ReactCommon/utils/BUCK +++ b/ReactCommon/utils/BUCK @@ -1,5 +1,5 @@ load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob") -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "get_apple_compiler_flags", "react_native_xplat_target", "rn_xplat_cxx_library") +load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "CXX", "get_apple_compiler_flags", "react_native_xplat_target", "rn_xplat_cxx_library") CXX_LIBRARY_COMPILER_FLAGS = [ "-std=c++14", @@ -21,7 +21,7 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = get_apple_compiler_flags(), force_static = True, - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), visibility = [ "PUBLIC", ], diff --git a/packages/react-native-codegen/DEFS.bzl b/packages/react-native-codegen/DEFS.bzl index 31fdfbdc091d25..308aabe71518e7 100644 --- a/packages/react-native-codegen/DEFS.bzl +++ b/packages/react-native-codegen/DEFS.bzl @@ -5,6 +5,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -123,7 +124,7 @@ def rn_codegen( ], fbobjc_compiler_flags = get_apple_compiler_flags(), fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -159,7 +160,7 @@ def rn_codegen( ], contacts = ["oncall+react_native@xmail.facebook.com"], apple_sdks = (IOS, MACOSX), - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/third-party/gmock:gtest", ":generated_components-{}".format(name), From a4cc519a52882a6b08825ecdb15e1c9411c0197d Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 4 Jun 2019 15:28:24 -0700 Subject: [PATCH 096/330] Fabric: Synthetic benchmarks for prop parsing infra Summary: And, btw, the tests show that performance of that is not so great: ``` Running /Users/shergin/fbsource/fbobjc/buck-out/cells/fbsource/gen/xplat/js/react-native-github/ReactCommon/fabric/core/benchmarks Run on (12 X 2900 MHz CPU s) CPU Caches: L1 Data 32K (x6) L1 Instruction 32K (x6) L2 Unified 262K (x6) L3 Unified 12582K (x1) -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- propParsingUsingComponentDescriptor 79630 ns 77991 ns 8864 propParsingUsingComponentDescriptorWithNoSourceProps 70200 ns 69099 ns 8362 ``` Which means 70ms per 1000 prop parsing processes. Reviewed By: JoshuaGross, mdvacca Differential Revision: D15608677 fbshipit-source-id: ed4feca489e1243adc73de4741c287256c3aaec3 --- ReactCommon/fabric/core/BUCK | 28 ++++++- .../tests/benchmarks/RawPropsBenchmark.cpp | 80 +++++++++++++++++++ 2 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index e10813059a83a9..5d744cfc674eae 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -1,3 +1,4 @@ +load("@fbsource//tools/build_defs:fb_xplat_cxx_binary.bzl", "fb_xplat_cxx_binary") load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") load( "//tools/build_defs/oss:rn_defs.bzl", @@ -70,8 +71,8 @@ rn_xplat_cxx_library( fb_xplat_cxx_test( name = "tests", - srcs = glob(["tests/**/*.cpp"]), - headers = glob(["tests/**/*.h"]), + srcs = glob(["tests/*.cpp"]), + headers = glob(["tests/*.h"]), compiler_flags = [ "-fexceptions", "-frtti", @@ -86,3 +87,26 @@ fb_xplat_cxx_test( ":core", ], ) + +fb_xplat_cxx_binary( + name = "benchmarks", + srcs = glob(["tests/benchmarks/*.cpp"]), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + "-Wno-unused-variable", + ], + contacts = ["oncall+react_native@xmail.facebook.com"], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + platforms = (ANDROID, APPLE, CXX), + visibility = ["PUBLIC"], + deps = [ + "fbsource//xplat/third-party/benchmark:benchmark", + react_native_xplat_target("utils:utils"), + react_native_xplat_target("fabric/components/view:view"), + ":core", + ], +) diff --git a/ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp b/ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp new file mode 100644 index 00000000000000..5772849a6600c7 --- /dev/null +++ b/ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp @@ -0,0 +1,80 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +auto contextContainer = std::make_shared(); +auto eventDispatcher = std::shared_ptr{nullptr}; +auto viewComponentDescriptor = + ViewComponentDescriptor(eventDispatcher, contextContainer); + +auto emptyPropsDynamic = folly::parseJson("{}"); +auto propsString = std::string{ + "{\"flex\": 1, \"padding\": 10, \"position\": \"absolute\", \"display\": \"none\", \"nativeID\": \"some-id\", \"direction\": \"rtl\"}"}; +auto propsDynamic = folly::parseJson(propsString); +auto propsStringWithSomeUnsupportedProps = std::string{ + "{\"someName1\": 1, \"someName2\": 10, \"someName3\": \"absolute\", \"someName4\": \"none\", \"someName5\": \"some-id\", \"someName6\": \"rtl\"}"}; +auto unsupportedPropsDynamic = + folly::parseJson(propsStringWithSomeUnsupportedProps); + +auto sourceProps = ViewProps{}; +auto sharedSourceProps = ViewShadowNode::defaultSharedProps(); + +static void emptyPropCreation(benchmark::State &state) { + for (auto _ : state) { + ViewProps{}; + } +} +BENCHMARK(emptyPropCreation); + +static void propParsingEmptyRawProps(benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps( + sharedSourceProps, RawProps{emptyPropsDynamic}); + } +} +BENCHMARK(propParsingEmptyRawProps); + +static void propParsingRegularRawProps(benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps( + sharedSourceProps, RawProps{propsDynamic}); + } +} +BENCHMARK(propParsingRegularRawProps); + +static void propParsingUnsupportedRawProps(benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps( + sharedSourceProps, RawProps{unsupportedPropsDynamic}); + } +} +BENCHMARK(propParsingUnsupportedRawProps); + +static void propParsingRegularRawPropsWithNoSourceProps( + benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps(nullptr, RawProps{propsDynamic}); + } +} +BENCHMARK(propParsingRegularRawPropsWithNoSourceProps); + +} // namespace react +} // namespace facebook + +BENCHMARK_MAIN(); From 920d9dea21f217ca647e69d4f941f99c60c36143 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 4 Jun 2019 19:18:05 -0700 Subject: [PATCH 097/330] Fix typo in layout time Summary: Fix typo. Reviewed By: shergin Differential Revision: D15639194 fbshipit-source-id: 1e1d029aab2a7016c630c7429815531e63f71333 --- ReactCommon/fabric/mounting/MountingTelemetry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/mounting/MountingTelemetry.cpp b/ReactCommon/fabric/mounting/MountingTelemetry.cpp index a6964bd6b7165f..5f5bdf30ab7a2d 100644 --- a/ReactCommon/fabric/mounting/MountingTelemetry.cpp +++ b/ReactCommon/fabric/mounting/MountingTelemetry.cpp @@ -35,7 +35,7 @@ void MountingTelemetry::willLayout() { void MountingTelemetry::didLayout() { assert(layoutStartTime_ != kUndefinedTime); assert(layoutEndTime_ == kUndefinedTime); - layoutEndTime_ -= getTime(); + layoutEndTime_ = getTime(); } int64_t MountingTelemetry::getCommitTime() const { From 7cf939b0ad1ffb2a2dd87a4d4f5cf3f0c0c2dacf Mon Sep 17 00:00:00 2001 From: Kody Greenbaum Date: Wed, 5 Jun 2019 01:46:44 -0700 Subject: [PATCH 098/330] Back out "[react-native][PR] [Blob] Release underlying resources when JS instance is GC'ed on Android" Summary: Testing if reverting this fixes the android instacrash. Original commit changeset: 2bbdc4bbcbea Reviewed By: cpojer Differential Revision: D15611385 fbshipit-source-id: 396fc0698e1056c93dbb154f95c8cc13924d5495 --- RNTester/android/app/BUCK | 1 - ReactAndroid/build.gradle | 1 - .../java/com/facebook/react/modules/blob/BUCK | 2 - .../react/modules/blob/BlobCollector.java | 25 -------- .../react/modules/blob/BlobModule.java | 39 +++++------- .../react/modules/blob/jni/Android.mk | 21 ------- .../com/facebook/react/modules/blob/jni/BUCK | 22 ------- .../react/modules/blob/jni/BlobCollector.cpp | 61 ------------------- .../react/modules/blob/jni/BlobCollector.h | 39 ------------ .../react/modules/blob/jni/OnLoad.cpp | 13 ---- .../src/main/jni/react/jni/Android.mk | 2 - 11 files changed, 15 insertions(+), 211 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp diff --git a/RNTester/android/app/BUCK b/RNTester/android/app/BUCK index 5e839d5e9153ca..ceb05c3e109291 100644 --- a/RNTester/android/app/BUCK +++ b/RNTester/android/app/BUCK @@ -25,7 +25,6 @@ rn_android_library( react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/common:build_config"), react_native_target("java/com/facebook/react/modules/core:core"), - react_native_target("java/com/facebook/react/views/text:text"), react_native_target("java/com/facebook/react/shell:shell"), react_native_target("jni/prebuilt:android-jsc"), # .so files are prebuilt by Gradle with `./gradlew :ReactAndroid:packageReactNdkLibsForBuck` diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 343543143431bc..81e2d74ac759cd 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -225,7 +225,6 @@ def getNdkBuildFullPath() { task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog], type: Exec) { inputs.dir("$projectDir/../ReactCommon") inputs.dir("src/main/jni") - inputs.dir("src/main/java/com/facebook/react/modules/blob") outputs.dir("$buildDir/react-ndk/all") commandLine(getNdkBuildFullPath(), "NDK_DEBUG=" + (nativeBuildType.equalsIgnoreCase("debug") ? "1" : "0"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index 72c927348f08e4..ac8fbcbc9f87ec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -16,7 +16,6 @@ rn_android_library( ], deps = [ react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), - react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/java/okhttp:okhttp3"), @@ -25,7 +24,6 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), - react_native_target("java/com/facebook/react/modules/blob/jni:jni"), react_native_target("java/com/facebook/react/modules/network:network"), react_native_target("java/com/facebook/react/modules/websocket:websocket"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java deleted file mode 100644 index 715f3dd38f6300..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.facebook.react.modules.blob; - -import com.facebook.react.bridge.JavaScriptContextHolder; -import com.facebook.react.bridge.ReactContext; -import com.facebook.soloader.SoLoader; - -/* package */ class BlobCollector { - static { - SoLoader.loadLibrary("reactnativeblob"); - } - - static void install(final ReactContext reactContext, final BlobModule blobModule) { - reactContext.runOnJSQueueThread(new Runnable() { - @Override - public void run() { - JavaScriptContextHolder jsContext = reactContext.getJavaScriptContextHolder(); - synchronized (jsContext) { - nativeInstall(blobModule, jsContext.get()); - } - } - }); - } - - private native static void nativeInstall(Object blobModule, long jsContext); -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 7bb5f281e49118..830180c6ffc308 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -6,10 +6,13 @@ */ package com.facebook.react.modules.blob; +import android.content.ContentResolver; +import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; +import androidx.annotation.Nullable; import android.webkit.MimeTypeMap; import com.facebook.react.bridge.Arguments; @@ -37,7 +40,6 @@ import java.util.Map; import java.util.UUID; -import androidx.annotation.Nullable; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.ResponseBody; @@ -149,11 +151,6 @@ public BlobModule(ReactApplicationContext reactContext) { super(reactContext); } - @Override - public void initialize() { - BlobCollector.install(getReactApplicationContext(), this); - } - @Override public String getName() { return NAME; @@ -181,15 +178,11 @@ public String store(byte[] data) { } public void store(byte[] data, String blobId) { - synchronized (mBlobs) { - mBlobs.put(blobId, data); - } + mBlobs.put(blobId, data); } public void remove(String blobId) { - synchronized (mBlobs) { - mBlobs.remove(blobId); - } + mBlobs.remove(blobId); } public @Nullable byte[] resolve(Uri uri) { @@ -208,19 +201,17 @@ public void remove(String blobId) { } public @Nullable byte[] resolve(String blobId, int offset, int size) { - synchronized (mBlobs) { - byte[] data = mBlobs.get(blobId); - if (data == null) { - return null; - } - if (size == -1) { - size = data.length - offset; - } - if (offset > 0 || size != data.length) { - data = Arrays.copyOfRange(data, offset, offset + size); - } - return data; + byte[] data = mBlobs.get(blobId); + if (data == null) { + return null; + } + if (size == -1) { + size = data.length - offset; + } + if (offset > 0 || size != data.length) { + data = Arrays.copyOfRange(data, offset, offset + size); } + return data; } public @Nullable byte[] resolve(ReadableMap blob) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk deleted file mode 100644 index b0ef370c574413..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := reactnativeblob - -LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) - -LOCAL_C_INCLUDES := $(LOCAL_PATH) - -LOCAL_CFLAGS += -fvisibility=hidden -fexceptions -frtti - -LOCAL_STATIC_LIBRARIES := libjsi libjsireact jscruntime -LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni - -include $(BUILD_SHARED_LIBRARY) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK deleted file mode 100644 index c02646779b63f8..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK +++ /dev/null @@ -1,22 +0,0 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library") - -rn_xplat_cxx_library( - name = "jni", - srcs = glob(["*.cpp"]), - headers = glob(["*.h"]), - header_namespace = "", - compiler_flags = ["-fexceptions"], - fbandroid_allow_jni_merging = True, - platforms = ANDROID, - soname = "libreactnativeblob.$(ext)", - visibility = [ - "PUBLIC", - ], - deps = [ - "fbsource//xplat/folly:molly", - FBJNI_TARGET, - react_native_target("jni/react/jni:jni"), - react_native_xplat_target("jsi:JSCRuntime"), - react_native_xplat_target("jsiexecutor:jsiexecutor"), - ], -) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp deleted file mode 100644 index d14d3885253b9d..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include "BlobCollector.h" - -#include -#include -#include - -using namespace facebook; - -namespace facebook { -namespace react { - -static constexpr auto kBlobModuleJavaDescriptor = - "com/facebook/react/modules/blob/BlobModule"; - -BlobCollector::BlobCollector( - jni::global_ref blobModule, - const std::string &blobId) - : blobModule_(blobModule), blobId_(blobId) {} - -BlobCollector::~BlobCollector() { - auto removeMethod = jni::findClassStatic(kBlobModuleJavaDescriptor) - ->getMethod("remove"); - removeMethod(blobModule_, jni::make_jstring(blobId_).get()); -} - -void BlobCollector::nativeInstall( - jni::alias_ref jThis, - jni::alias_ref blobModule, - jlong jsContextNativePointer) { - auto &runtime = *((jsi::Runtime *)jsContextNativePointer); - auto blobModuleRef = jni::make_global(blobModule); - runtime.global().setProperty( - runtime, - "__blobCollectorProvider", - jsi::Function::createFromHostFunction( - runtime, - jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"), - 1, - [blobModuleRef]( - jsi::Runtime &rt, - const jsi::Value &thisVal, - const jsi::Value *args, - size_t count) { - auto blobId = args[0].asString(rt).utf8(rt); - auto blobCollector = - std::make_shared(blobModuleRef, blobId); - return jsi::Object::createFromHostObject(rt, blobCollector); - })); -} - -void BlobCollector::registerNatives() { - registerHybrid( - {makeNativeMethod("nativeInstall", BlobCollector::nativeInstall)}); -} - -} // namespace react -} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h deleted file mode 100644 index b013cf8bf665c7..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#pragma once - -#include -#include - -namespace facebook { -namespace react { - -class BlobCollector : public jni::HybridClass, - public jsi::HostObject { - public: - BlobCollector( - jni::global_ref blobManager, - const std::string &blobId); - ~BlobCollector(); - - static constexpr auto kJavaDescriptor = - "Lcom/facebook/react/modules/blob/BlobCollector;"; - - static void nativeInstall( - jni::alias_ref jThis, - jni::alias_ref blobModule, - jlong jsContextNativePointer); - - static void registerNatives(); - - private: - friend HybridBase; - - jni::global_ref blobModule_; - const std::string blobId_; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp deleted file mode 100644 index 3707d02665e44a..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include - -#include "BlobCollector.h" - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { - return facebook::jni::initialize( - vm, [] { facebook::react::BlobCollector::registerNatives(); }); -} diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 28c1fae096e7bf..b2422db96598f0 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -76,5 +76,3 @@ include $(REACT_SRC_DIR)/turbomodule/core/jni/Android.mk # $(call import-module,jscexecutor) include $(REACT_SRC_DIR)/jscexecutor/Android.mk - -include $(REACT_SRC_DIR)/modules/blob/jni/Android.mk From 69d1ed731bf52c8b99f8b6319398b3920dcec109 Mon Sep 17 00:00:00 2001 From: James Ide Date: Wed, 5 Jun 2019 04:14:52 -0700 Subject: [PATCH 099/330] Sync React with Haste-style imports rewritten to use path-based imports instead (#25100) Summary: **This is a manual React sync to replace Haste names with paths so that the removal of Haste is not blocked on a normal React sync. This is a one-time special case; in the future, React will generate renderers that use paths instead of Haste.** This commit uses the same base commit of React that's currently in RN (React ec6691a68716bc59291746fc62f374a56fb435c9) plus a commit in the React repo that removes Haste-style imports from the renderer (61f62246c8cfb76a4a19d1661eeaa5822ec37b36) and a commit to make the shims import from `implementations` (https://github.com/facebook/react/pull/15786). I built React in the React repo with `yarn build` and copied over the `oss` directory into one called `implementations` and removed the `*.fb.js` files. ## Changelog [General] [Changed] - Sync React with Haste-style imports rewritten to use path-based imports instead Pull Request resolved: https://github.com/facebook/react-native/pull/25100 Reviewed By: yungsters Differential Revision: D15575646 Pulled By: cpojer fbshipit-source-id: adf25f9826b71729043b65ba1afd20d14d8c19c4 --- Libraries/Renderer/REVISION | 2 +- .../implementations/ReactFabric-dev.fb.js | 19816 +++++++++++++++ .../ReactFabric-dev.js | 211 +- .../implementations/ReactFabric-prod.fb.js | 6974 ++++++ .../ReactFabric-prod.js | 171 +- .../ReactFabric-profiling.fb.js | 7211 ++++++ .../ReactFabric-profiling.js | 173 +- .../ReactNativeRenderer-dev.fb.js | 20167 ++++++++++++++++ .../ReactNativeRenderer-dev.js | 185 +- .../ReactNativeRenderer-prod.fb.js | 7205 ++++++ .../ReactNativeRenderer-prod.js | 186 +- .../ReactNativeRenderer-profiling.fb.js | 7445 ++++++ .../ReactNativeRenderer-profiling.js | 188 +- Libraries/Renderer/shims/ReactFabric.js | 6 +- Libraries/Renderer/shims/ReactFeatureFlags.js | 17 + Libraries/Renderer/shims/ReactNative.js | 4 +- .../shims/createReactNativeComponentClass.js | 4 +- 17 files changed, 69476 insertions(+), 489 deletions(-) create mode 100644 Libraries/Renderer/implementations/ReactFabric-dev.fb.js rename Libraries/Renderer/{oss => implementations}/ReactFabric-dev.js (99%) create mode 100644 Libraries/Renderer/implementations/ReactFabric-prod.fb.js rename Libraries/Renderer/{oss => implementations}/ReactFabric-prod.js (97%) create mode 100644 Libraries/Renderer/implementations/ReactFabric-profiling.fb.js rename Libraries/Renderer/{oss => implementations}/ReactFabric-profiling.js (98%) create mode 100644 Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js rename Libraries/Renderer/{oss => implementations}/ReactNativeRenderer-dev.js (99%) create mode 100644 Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js rename Libraries/Renderer/{oss => implementations}/ReactNativeRenderer-prod.js (97%) create mode 100644 Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js rename Libraries/Renderer/{oss => implementations}/ReactNativeRenderer-profiling.js (98%) create mode 100644 Libraries/Renderer/shims/ReactFeatureFlags.js diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 7a8c0a1ac2f570..ca2ac7272eb294 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -ec6691a68716bc59291746fc62f374a56fb435c9 \ No newline at end of file +87d375afd0d9394646a4bcddcebb7b15ffaa7e9e \ No newline at end of file diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js new file mode 100644 index 00000000000000..01a54327173ccf --- /dev/null +++ b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -0,0 +1,19816 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +'use strict'; + +if (__DEV__) { + (function() { +"use strict"; + +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); +var React = require("react"); +var checkPropTypes = require("prop-types/checkPropTypes"); +var Scheduler = require("scheduler"); +var tracing = require("scheduler/tracing"); + +// Do not require this module directly! Use a normal error constructor with +// template literal strings. The messages will be converted to ReactError during +// build, and in production they will be minified. + +function ReactError(message) { + var error = new Error(message); + error.name = "Invariant Violation"; + return error; +} + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; + +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; + +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; + var pluginIndex = eventPluginOrder.indexOf(pluginName); + (function() { + if (!(pluginIndex > -1)) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + } + })(); + if (plugins[pluginIndex]) { + continue; + } + (function() { + if (!pluginModule.extractEvents) { + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + } + })(); + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + (function() { + if ( + !publishEventForPlugin( + publishedEvents[eventName], + pluginModule, + eventName + ) + ) { + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + })(); + } + } +} + +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + (function() { + if (!!eventNameDispatchConfigs.hasOwnProperty(eventName)) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName + + "`." + ); + } + })(); + eventNameDispatchConfigs[eventName] = dispatchConfig; + + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName( + phasedRegistrationName, + pluginModule, + eventName + ); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName( + dispatchConfig.registrationName, + pluginModule, + eventName + ); + return true; + } + return false; +} + +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + (function() { + if (!!registrationNameModules[registrationName]) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + } + })(); + registrationNameModules[registrationName] = pluginModule; + registrationNameDependencies[registrationName] = + pluginModule.eventTypes[eventName].dependencies; + + { + var lowerCasedName = registrationName.toLowerCase(); + } +} + +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ + +/** + * Ordered list of injected plugins. + */ +var plugins = []; + +/** + * Mapping from event name to dispatch config + */ +var eventNameDispatchConfigs = {}; + +/** + * Mapping from registration name to plugin module + */ +var registrationNameModules = {}; + +/** + * Mapping from registration name to event name + */ +var registrationNameDependencies = {}; + +/** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ + +// Trust the developer to only use possibleRegistrationNames in true + +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ +function injectEventPluginOrder(injectedEventPluginOrder) { + (function() { + if (!!eventPluginOrder) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + } + })(); + // Clone the ordering so it cannot be dynamically mutated. + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} + +/** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + (function() { + if (!!namesToPlugins[pluginName]) { + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + } + })(); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} + +var invokeGuardedCallbackImpl = function( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +}; + +{ + // In DEV mode, we swap out invokeGuardedCallback for a special version + // that plays more nicely with the browser's DevTools. The idea is to preserve + // "Pause on exceptions" behavior. Because React wraps all user-provided + // functions in invokeGuardedCallback, and the production version of + // invokeGuardedCallback uses a try-catch, all user exceptions are treated + // like caught exceptions, and the DevTools won't pause unless the developer + // takes the extra step of enabling pause on caught exceptions. This is + // unintuitive, though, because even though React has caught the error, from + // the developer's perspective, the error is uncaught. + // + // To preserve the expected "Pause on exceptions" behavior, we don't use a + // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake + // DOM node, and call the user-provided callback from inside an event handler + // for that fake event. If the callback throws, the error is "captured" using + // a global event handler. But because the error happens in a different + // event loop context, it does not interrupt the normal program flow. + // Effectively, this gives us try-catch behavior without actually using + // try-catch. Neat! + + // Check that the browser supports the APIs we need to implement our special + // DEV version of invokeGuardedCallback + if ( + typeof window !== "undefined" && + typeof window.dispatchEvent === "function" && + typeof document !== "undefined" && + typeof document.createEvent === "function" + ) { + var fakeNode = document.createElement("react"); + + var invokeGuardedCallbackDev = function( + name, + func, + context, + a, + b, + c, + d, + e, + f + ) { + // If document doesn't exist we know for sure we will crash in this method + // when we call document.createEvent(). However this can cause confusing + // errors: https://github.com/facebookincubator/create-react-app/issues/3482 + // So we preemptively throw with a better message instead. + (function() { + if (!(typeof document !== "undefined")) { + throw ReactError( + "The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous." + ); + } + })(); + var evt = document.createEvent("Event"); + + // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError = true; + + // Keeps track of the value of window.event so that we can reset it + // during the callback to let user code access window.event in the + // browsers that support it. + var windowEvent = window.event; + + // Keeps track of the descriptor of window.event to restore it after event + // dispatching: https://github.com/facebook/react/issues/13688 + var windowEventDescriptor = Object.getOwnPropertyDescriptor( + window, + "event" + ); + + // Create an event handler for our fake event. We will synchronously + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. + var funcArgs = Array.prototype.slice.call(arguments, 3); + function callCallback() { + // We immediately remove the callback from event listeners so that + // nested `invokeGuardedCallback` calls do not clash. Otherwise, a + // nested call would trigger the fake event handlers of any call higher + // in the stack. + fakeNode.removeEventListener(evtType, callCallback, false); + + // We check for window.hasOwnProperty('event') to prevent the + // window.event assignment in both IE <= 10 as they throw an error + // "Member not found" in strict mode, and in Firefox which does not + // support window.event. + if ( + typeof window.event !== "undefined" && + window.hasOwnProperty("event") + ) { + window.event = windowEvent; + } + + func.apply(context, funcArgs); + didError = false; + } + + // Create a global error event handler. We use this to capture the value + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error = void 0; + // Use this to track whether the error event is ever called. + var didSetError = false; + var isCrossOriginError = false; + + function handleWindowError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + if (event.defaultPrevented) { + // Some other error handler has prevented default. + // Browsers silence the error report if this happens. + // We'll remember this to later decide whether to log it or not. + if (error != null && typeof error === "object") { + try { + error._suppressLogging = true; + } catch (inner) { + // Ignore. + } + } + } + } + + // Create a fake event type. + var evtType = "react-" + (name ? name : "invokeguardedcallback"); + + // Attach our event handlers + window.addEventListener("error", handleWindowError); + fakeNode.addEventListener(evtType, callCallback, false); + + // Synchronously dispatch our fake event. If the user-provided function + // errors, it will trigger our global error handler. + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + + if (windowEventDescriptor) { + Object.defineProperty(window, "event", windowEventDescriptor); + } + + if (didError) { + if (!didSetError) { + // The callback errored, but the error event never fired. + error = new Error( + "An error was thrown inside one of your components, but React " + + "doesn't know what it was. This is likely due to browser " + + 'flakiness. React does its best to preserve the "Pause on ' + + 'exceptions" behavior of the DevTools, which requires some ' + + "DEV-mode only tricks. It's possible that these don't work in " + + "your browser. Try triggering the error in production mode, " + + "or switching to a modern browser. If you suspect that this is " + + "actually an issue with React, please file an issue." + ); + } else if (isCrossOriginError) { + error = new Error( + "A cross-origin error was thrown. React doesn't have access to " + + "the actual error object in development. " + + "See https://fb.me/react-crossorigin-error for more information." + ); + } + this.onError(error); + } + + // Remove our event listeners + window.removeEventListener("error", handleWindowError); + }; + + invokeGuardedCallbackImpl = invokeGuardedCallbackDev; + } +} + +var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; + +// Used by Fiber to simulate a try-catch. +var hasError = false; +var caughtError = null; + +// Used by event system to capture/rethrow the first error. +var hasRethrowError = false; +var rethrowError = null; + +var reporter = { + onError: function(error) { + hasError = true; + caughtError = error; + } +}; + +/** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = false; + caughtError = null; + invokeGuardedCallbackImpl$1.apply(reporter, arguments); +} + +/** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if caughtError and rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + var error = clearCaughtError(); + if (!hasRethrowError) { + hasRethrowError = true; + rethrowError = error; + } + } +} + +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ +function rethrowCaughtError() { + if (hasRethrowError) { + var error = rethrowError; + hasRethrowError = false; + rethrowError = null; + throw error; + } +} + +function hasCaughtError() { + return hasError; +} + +function clearCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + return error; + } else { + (function() { + { + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warningWithoutStack = function() {}; + +{ + warningWithoutStack = function(condition, format) { + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + if (format === undefined) { + throw new Error( + "`warningWithoutStack(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (args.length > 8) { + // Check before the condition to catch violations early. + throw new Error( + "warningWithoutStack() currently supports at most 8 arguments." + ); + } + if (condition) { + return; + } + if (typeof console !== "undefined") { + var argsWithFormat = args.map(function(item) { + return "" + item; + }); + argsWithFormat.unshift("Warning: " + format); + + // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + Function.prototype.apply.call(console.error, console, argsWithFormat); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + throw new Error(message); + } catch (x) {} + }; +} + +var warningWithoutStack$1 = warningWithoutStack; + +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; + +function setComponentTree( + getFiberCurrentPropsFromNodeImpl, + getInstanceFromNodeImpl, + getNodeFromInstanceImpl +) { + getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode = getInstanceFromNodeImpl; + getNodeFromInstance = getNodeFromInstanceImpl; + { + !(getNodeFromInstance && getInstanceFromNode) + ? warningWithoutStack$1( + false, + "EventPluginUtils.setComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; + } +} + +var validateEventDispatches = void 0; +{ + validateEventDispatches = function(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + + var listenersIsArr = Array.isArray(dispatchListeners); + var listenersLen = listenersIsArr + ? dispatchListeners.length + : dispatchListeners + ? 1 + : 0; + + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr + ? dispatchInstances.length + : dispatchInstances + ? 1 + : 0; + + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) + ? warningWithoutStack$1(false, "EventPluginUtils: Invalid `event`.") + : void 0; + }; +} + +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); + } + event._dispatchListeners = null; + event._dispatchInstances = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return {?string} id of the first dispatch execution who's listener returns + * true, or null if no listener returned true. + */ +function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; + } + } + return null; +} + +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ +function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchInstances = null; + event._dispatchListeners = null; + return ret; +} + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ +function executeDirectDispatch(event) { + { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchInstance = event._dispatchInstances; + (function() { + if (!!Array.isArray(dispatchListener)) { + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + } + })(); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return res; +} + +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ +function hasDispatches(event) { + return !!event._dispatchListeners; +} + +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ + +function accumulateInto(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + if (Array.isArray(next)) { + current.push.apply(current, next); + return current; + } + current.push(next); + return current; + } + + if (Array.isArray(next)) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } + + return [current, next]; +} + +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; + +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function(event) { + if (event) { + executeDispatchesInOrder(event); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; +var executeDispatchesAndReleaseTopLevel = function(e) { + return executeDispatchesAndRelease(e); +}; + +function runEventsInBatch(events) { + if (events !== null) { + eventQueue = accumulateInto(eventQueue, events); + } + + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + + if (!processingEventQueue) { + return; + } + + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + (function() { + if (!!eventQueue) { + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + } + })(); + // This would be a good time to rethrow if any of the event handlers threw. + rethrowCaughtError(); +} + +function isInteractive(tag) { + return ( + tag === "button" || + tag === "input" || + tag === "select" || + tag === "textarea" + ); +} + +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + return !!(props.disabled && isInteractive(type)); + default: + return false; + } +} + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ + +/** + * Methods for injecting dependencies. + */ +var injection = { + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: injectEventPluginsByName +}; + +/** + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ +function getListener(inst, registrationName) { + var listener = void 0; + + // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not + // live here; needs to be moved to a better place soon + var stateNode = inst.stateNode; + if (!stateNode) { + // Work in progress (ex: onload events in incremental mode). + return null; + } + var props = getFiberCurrentPropsFromNode(stateNode); + if (!props) { + // Work in progress. + return null; + } + listener = props[registrationName]; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; + } + (function() { + if (!(!listener || typeof listener === "function")) { + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + } + })(); + return listener; +} + +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ +function extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = null; + for (var i = 0; i < plugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } + } + return events; +} + +function runExtractedPluginEventsInBatch( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + runEventsInBatch(events); +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var IndeterminateComponent = 2; // Before we know whether it is function or class +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedSuspenseComponent = 18; +var EventComponent = 19; +var EventTarget = 20; + +function getParent(inst) { + do { + inst = inst.return; + // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + if (inst) { + return inst; + } + return null; +} + +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + for (var tempA = instA; tempA; tempA = getParent(tempA)) { + depthA++; + } + var depthB = 0; + for (var tempB = instB; tempB; tempB = getParent(tempB)) { + depthB++; + } + + // If A is deeper, crawl up. + while (depthA - depthB > 0) { + instA = getParent(instA); + depthA--; + } + + // If B is deeper, crawl up. + while (depthB - depthA > 0) { + instB = getParent(instB); + depthB--; + } + + // Walk in lockstep until we find a match. + var depth = depthA; + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; + } + instA = getParent(instA); + instB = getParent(instB); + } + return null; +} + +/** + * Return if A is an ancestor of B. + */ +function isAncestor(instA, instB) { + while (instB) { + if (instA === instB || instA === instB.alternate) { + return true; + } + instB = getParent(instB); + } + return false; +} + +/** + * Return the parent instance of the passed-in instance. + */ +function getParentInstance(inst) { + return getParent(inst); +} + +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ +function traverseTwoPhase(inst, fn, arg) { + var path = []; + while (inst) { + path.push(inst); + inst = getParent(inst); + } + var i = void 0; + for (i = path.length; i-- > 0; ) { + fn(path[i], "captured", arg); + } + for (i = 0; i < path.length; i++) { + fn(path[i], "bubbled", arg); + } +} + +/** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * Does not invoke the callback on the nearest common ancestor because nothing + * "entered" or "left" that element. + */ + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = + event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing even a + * single one. + */ + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(inst, phase, event) { + { + !inst + ? warningWithoutStack$1(false, "Dispatching inst must not be null") + : void 0; + } + var listener = listenerAtPhase(inst, event, phase); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We cannot perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. + */ +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? getParentInstance(targetInst) : null; + traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); +} + +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} + +/* eslint valid-typeof: 0 */ + +var EVENT_POOL_SIZE = 10; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +function functionThatReturnsTrue() { + return true; +} + +function functionThatReturnsFalse() { + return false; +} + +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; + } + + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } + { + delete this[propName]; // this has a getter/setter for warnings + } + var normalize = Interface[propName]; + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === "target") { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } + + var defaultPrevented = + nativeEvent.defaultPrevented != null + ? nativeEvent.defaultPrevented + : nativeEvent.returnValue === false; + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} + +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = true; + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== "unknown") { + event.returnValue = false; + } + this.isDefaultPrevented = functionThatReturnsTrue; + }, + + stopPropagation: function() { + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== "unknown") { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } + + this.isPropagationStopped = functionThatReturnsTrue; + }, + + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, + + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function() { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + { + Object.defineProperty( + this, + propName, + getPooledWarningPropertyDefinition(propName, Interface[propName]) + ); + } + } + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; + { + Object.defineProperty( + this, + "nativeEvent", + getPooledWarningPropertyDefinition("nativeEvent", null) + ); + Object.defineProperty( + this, + "isDefaultPrevented", + getPooledWarningPropertyDefinition( + "isDefaultPrevented", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "isPropagationStopped", + getPooledWarningPropertyDefinition( + "isPropagationStopped", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "preventDefault", + getPooledWarningPropertyDefinition("preventDefault", function() {}) + ); + Object.defineProperty( + this, + "stopPropagation", + getPooledWarningPropertyDefinition("stopPropagation", function() {}) + ); + } + } +}); + +SyntheticEvent.Interface = EventInterface; + +/** + * Helper to reduce boilerplate when creating subclasses. + */ +SyntheticEvent.extend = function(Interface) { + var Super = this; + + var E = function() {}; + E.prototype = Super.prototype; + var prototype = new E(); + + function Class() { + return Super.apply(this, arguments); + } + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + + return Class; +}; + +addEventPoolingTo(SyntheticEvent); + +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ +function getPooledWarningPropertyDefinition(propName, getVal) { + var isFunction = typeof getVal === "function"; + return { + configurable: true, + set: set, + get: get + }; + + function set(val) { + var action = isFunction ? "setting the method" : "setting the property"; + warn(action, "This is effectively a no-op"); + return val; + } + + function get() { + var action = isFunction ? "accessing the method" : "accessing the property"; + var result = isFunction + ? "This is a no-op function" + : "This is set to null"; + warn(action, result); + return getVal; + } + + function warn(action, result) { + var warningCondition = false; + !warningCondition + ? warningWithoutStack$1( + false, + "This synthetic event is reused for performance reasons. If you're seeing this, " + + "you're %s `%s` on a released/nullified synthetic event. %s. " + + "If you must keep the original synthetic event around, use event.persist(). " + + "See https://fb.me/react-event-pooling for more information.", + action, + propName, + result + ) + : void 0; + } +} + +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call( + instance, + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); + return instance; + } + return new EventConstructor( + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); +} + +function releasePooledEvent(event) { + var EventConstructor = this; + (function() { + if (!(event instanceof EventConstructor)) { + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + } + })(); + event.destructor(); + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} + +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} + +/** + * `touchHistory` isn't actually on the native event, but putting it in the + * interface will ensure that it is cleaned up when pooled/destroyed. The + * `ResponderEventPlugin` will populate it appropriately. + */ +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function(nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +var TOP_TOUCH_START = "topTouchStart"; +var TOP_TOUCH_MOVE = "topTouchMove"; +var TOP_TOUCH_END = "topTouchEnd"; +var TOP_TOUCH_CANCEL = "topTouchCancel"; +var TOP_SCROLL = "topScroll"; +var TOP_SELECTION_CHANGE = "topSelectionChange"; + +function isStartish(topLevelType) { + return topLevelType === TOP_TOUCH_START; +} + +function isMoveish(topLevelType) { + return topLevelType === TOP_TOUCH_MOVE; +} + +function isEndish(topLevelType) { + return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL; +} + +var startDependencies = [TOP_TOUCH_START]; +var moveDependencies = [TOP_TOUCH_MOVE]; +var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; + +/** + * Tracks the position and time of each active touch by `touch.identifier`. We + * should typically only see IDs in the range of 1-20 because IDs get recycled + * when touches end and start again. + */ + +var MAX_TOUCH_BANK = 20; +var touchBank = []; +var touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + // If there is only one active touch, we remember its location. This prevents + // us having to loop through all of the touches all the time in the most + // common case. + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 +}; + +function timestampForTouch(touch) { + // The legacy internal implementation provides "timeStamp", which has been + // renamed to "timestamp". Let both work for now while we iron it out + // TODO (evv): rename timeStamp to timestamp in internal code + return touch.timeStamp || touch.timestamp; +} + +/** + * TODO: Instead of making gestures recompute filtered velocity, we could + * include a built in velocity computation that can be reused globally. + */ +function createTouchRecord(touch) { + return { + touchActive: true, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }; +} + +function resetTouchRecord(touchRecord, touch) { + touchRecord.touchActive = true; + touchRecord.startPageX = touch.pageX; + touchRecord.startPageY = touch.pageY; + touchRecord.startTimeStamp = timestampForTouch(touch); + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchRecord.previousPageX = touch.pageX; + touchRecord.previousPageY = touch.pageY; + touchRecord.previousTimeStamp = timestampForTouch(touch); +} + +function getTouchIdentifier(_ref) { + var identifier = _ref.identifier; + + (function() { + if (!(identifier != null)) { + throw ReactError("Touch object is missing identifier."); + } + })(); + { + !(identifier <= MAX_TOUCH_BANK) + ? warningWithoutStack$1( + false, + "Touch identifier %s is greater than maximum supported %s which causes " + + "performance issues backfilling array locations for all of the indices.", + identifier, + MAX_TOUCH_BANK + ) + : void 0; + } + return identifier; +} + +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch); + var touchRecord = touchBank[identifier]; + if (touchRecord) { + resetTouchRecord(touchRecord, touch); + } else { + touchBank[identifier] = createTouchRecord(touch); + } + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} + +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = true; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch move without a touch start.\n" + "Touch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = false; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch end without a touch start.\n" + "Touch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} + +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); + if (touchBank.length > MAX_TOUCH_BANK) { + printed += " (original size: " + touchBank.length + ")"; + } + return printed; +} + +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchMove); + } else if (isStartish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchStart); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier; + } + } else if (isEndish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchEnd); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + for (var i = 0; i < touchBank.length; i++) { + var touchTrackToCheck = touchBank[i]; + if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { + touchHistory.indexOfSingleActiveTouch = i; + break; + } + } + { + var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; + !(activeRecord != null && activeRecord.touchActive) + ? warningWithoutStack$1(false, "Cannot find single active touch.") + : void 0; + } + } + } + }, + + touchHistory: touchHistory +}; + +/** + * Accumulates items that must not be null or undefined. + * + * This is used to conserve memory by avoiding array allocations. + * + * @return {*|array<*>} An accumulation of items. + */ +function accumulate(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + return current.concat(next); + } + + if (Array.isArray(next)) { + return [current].concat(next); + } + + return [current, next]; +} + +/** + * Instance of element that should respond to touch/move types of interactions, + * as indicated explicitly by relevant callbacks. + */ +var responderInst = null; + +/** + * Count of current touches. A textInput should become responder iff the + * selection changes while there is a touch on the screen. + */ +var trackedTouchCount = 0; + +var changeResponder = function(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); + } +}; + +var eventTypes = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + + /** + * On a `scroll`, is it desired that this element become the responder? This + * is usually not needed, but should be used to retroactively infer that a + * `touchStart` had occurred during momentum scroll. During a momentum scroll, + * a touch start will be immediately followed by a scroll event if the view is + * currently scrolling. + * + * TODO: This shouldn't bubble. + */ + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: [TOP_SCROLL] + }, + + /** + * On text selection change, should this element become the responder? This + * is needed for text inputs or other views with native selection, so the + * JS view can claim the responder. + * + * TODO: This shouldn't bubble. + */ + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: [TOP_SELECTION_CHANGE] + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { + registrationName: "onResponderGrant", + dependencies: [] + }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } +}; + +/** + * + * Responder System: + * ---------------- + * + * - A global, solitary "interaction lock" on a view. + * - If a node becomes the responder, it should convey visual feedback + * immediately to indicate so, either by highlighting or moving accordingly. + * - To be the responder means, that touches are exclusively important to that + * responder view, and no other view. + * - While touches are still occurring, the responder lock can be transferred to + * a new view, but only to increasingly "higher" views (meaning ancestors of + * the current responder). + * + * Responder being granted: + * ------------------------ + * + * - Touch starts, moves, and scrolls can cause an ID to become the responder. + * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to + * the "appropriate place". + * - If nothing is currently the responder, the "appropriate place" is the + * initiating event's `targetID`. + * - If something *is* already the responder, the "appropriate place" is the + * first common ancestor of the event target and the current `responderInst`. + * - Some negotiation happens: See the timing diagram below. + * - Scrolled views automatically become responder. The reasoning is that a + * platform scroll view that isn't built on top of the responder system has + * began scrolling, and the active responder must now be notified that the + * interaction is no longer locked to it - the system has taken over. + * + * - Responder being released: + * As soon as no more touches that *started* inside of descendants of the + * *current* responderInst, an `onResponderRelease` event is dispatched to the + * current responder, and the responder lock is released. + * + * TODO: + * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that + * determines if the responder lock should remain. + * - If a view shouldn't "remain" the responder, any active touches should by + * default be considered "dead" and do not influence future negotiations or + * bubble paths. It should be as if those touches do not exist. + * -- For multitouch: Usually a translate-z will choose to "remain" responder + * after one out of many touches ended. For translate-y, usually the view + * doesn't wish to "remain" responder after one of many touches end. + * - Consider building this on top of a `stopPropagation` model similar to + * `W3C` events. + * - Ensure that `onResponderTerminate` is called on touch cancels, whether or + * not `onResponderTerminationRequest` returns `true` or `false`. + * + */ + +/* Negotiation Performed + +-----------------------+ + / \ +Process low level events to + Current Responder + wantsResponderID +determine who to perform negot-| (if any exists at all) | +iation/transition | Otherwise just pass through| +-------------------------------+----------------------------+------------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchStart| | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onStartShouldSetResponder|----->|onResponderStart (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderReject + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderStart| + | | +----------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchMove | | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onMoveShouldSetResponder |----->|onResponderMove (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderRejec| + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderMove | + | | +----------------+ + | | + | | + Some active touch started| | + inside current responder | +------------------------+ | + +------------------------->| onResponderEnd | | + | | +------------------------+ | + +---+---------+ | | + | onTouchEnd | | | + +---+---------+ | | + | | +------------------------+ | + +------------------------->| onResponderEnd | | + No active touches started| +-----------+------------+ | + inside current responder | | | + | v | + | +------------------------+ | + | | onResponderRelease | | + | +------------------------+ | + | | + + + */ + +/** + * A note about event ordering in the `EventPluginHub`. + * + * Suppose plugins are injected in the following order: + * + * `[R, S, C]` + * + * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for + * `onClick` etc) and `R` is `ResponderEventPlugin`. + * + * "Deferred-Dispatched Events": + * + * - The current event plugin system will traverse the list of injected plugins, + * in order, and extract events by collecting the plugin's return value of + * `extractEvents()`. + * - These events that are returned from `extractEvents` are "deferred + * dispatched events". + * - When returned from `extractEvents`, deferred-dispatched events contain an + * "accumulation" of deferred dispatches. + * - These deferred dispatches are accumulated/collected before they are + * returned, but processed at a later time by the `EventPluginHub` (hence the + * name deferred). + * + * In the process of returning their deferred-dispatched events, event plugins + * themselves can dispatch events on-demand without returning them from + * `extractEvents`. Plugins might want to do this, so that they can use event + * dispatching as a tool that helps them decide which events should be extracted + * in the first place. + * + * "On-Demand-Dispatched Events": + * + * - On-demand-dispatched events are not returned from `extractEvents`. + * - On-demand-dispatched events are dispatched during the process of returning + * the deferred-dispatched events. + * - They should not have side effects. + * - They should be avoided, and/or eventually be replaced with another + * abstraction that allows event plugins to perform multiple "rounds" of event + * extraction. + * + * Therefore, the sequence of event dispatches becomes: + * + * - `R`s on-demand events (if any) (dispatched by `R` on-demand) + * - `S`s on-demand events (if any) (dispatched by `S` on-demand) + * - `C`s on-demand events (if any) (dispatched by `C` on-demand) + * - `R`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `S`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `C`s extracted events (if any) (dispatched by `EventPluginHub`) + * + * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` + * on-demand dispatch returns `true` (and some other details are satisfied) the + * `onResponderGrant` deferred dispatched event is returned from + * `extractEvents`. The sequence of dispatch executions in this case + * will appear as follows: + * + * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) + * - `touchStartCapture` (`EventPluginHub` dispatches as usual) + * - `touchStart` (`EventPluginHub` dispatches as usual) + * - `responderGrant/Reject` (`EventPluginHub` dispatches as usual) + */ + +function setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var shouldSetEventType = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : topLevelType === TOP_SELECTION_CHANGE + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + + // TODO: stop one short of the current responder. + var bubbleShouldSetFrom = !responderInst + ? targetInst + : getLowestCommonAncestor(responderInst, targetInst); + + // When capturing/bubbling the "shouldSet" event, we want to skip the target + // (deepest ID) if it happens to be the current responder. The reasoning: + // It's strange to get an `onMoveShouldSetResponder` when you're *already* + // the responder. + var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; + var shouldSetEvent = ResponderSyntheticEvent.getPooled( + shouldSetEventType, + bubbleShouldSetFrom, + nativeEvent, + nativeEventTarget + ); + shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + if (skipOverBubbleShouldSetFrom) { + accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); + } else { + accumulateTwoPhaseDispatches(shouldSetEvent); + } + var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent); + if (!shouldSetEvent.isPersistent()) { + shouldSetEvent.constructor.release(shouldSetEvent); + } + + if (!wantsResponderInst || wantsResponderInst === responderInst) { + return null; + } + var extracted = void 0; + var grantEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + accumulateDirectDispatches(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminationRequestEvent.touchHistory = + ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminationRequestEvent); + var shouldSwitch = + !hasDispatches(terminationRequestEvent) || + executeDirectDispatch(terminationRequestEvent); + if (!terminationRequestEvent.isPersistent()) { + terminationRequestEvent.constructor.release(terminationRequestEvent); + } + + if (shouldSwitch) { + var terminateEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(rejectEvent); + extracted = accumulate(extracted, rejectEvent); + } + } else { + extracted = accumulate(extracted, grantEvent); + changeResponder(wantsResponderInst, blockHostResponder); + } + return extracted; +} + +/** + * A transfer is a negotiation between a currently set responder and the next + * element to claim responder status. Any start event could trigger a transfer + * of responderInst. Any move event could trigger a transfer. + * + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @return {boolean} True if a transfer of responder could possibly occur. + */ +function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { + return ( + topLevelInst && + // responderIgnoreScroll: We are trying to migrate away from specifically + // tracking native scroll events here and responderIgnoreScroll indicates we + // will send topTouchCancel to handle canceling touch events instead + ((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) || + (trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ); +} + +/** + * Returns whether or not this touch end event makes it such that there are no + * longer any touches that started inside of the current `responderInst`. + * + * @param {NativeEvent} nativeEvent Native touch end event. + * @return {boolean} Whether or not this touch end event ends the responder. + */ +function noResponderTouches(nativeEvent) { + var touches = nativeEvent.touches; + if (!touches || touches.length === 0) { + return true; + } + for (var i = 0; i < touches.length; i++) { + var activeTouch = touches[i]; + var target = activeTouch.target; + if (target !== null && target !== undefined && target !== 0) { + // Is the original touch location inside of the current responder? + var targetInst = getInstanceFromNode(target); + if (isAncestor(responderInst, targetInst)) { + return false; + } + } + } + return true; +} + +var ResponderEventPlugin = { + /* For unit testing only */ + _getResponder: function() { + return responderInst; + }, + + eventTypes: eventTypes, + + /** + * We must be resilient to `targetInst` being `null` on `touchMove` or + * `touchEnd`. On certain platforms, this means that a native scroll has + * assumed control and the original touch targets are destroyed. + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) { + trackedTouchCount += 1; + } else if (isEndish(topLevelType)) { + if (trackedTouchCount >= 0) { + trackedTouchCount -= 1; + } else { + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ); + return null; + } + } + + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + + var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) + ? setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) + : null; + // Responder may or may not have transferred on a new touch start/move. + // Regardless, whoever is the responder after any potential transfer, we + // direct all touch start/move/ends to them in the form of + // `onResponderMove/Start/End`. These will be called for *every* additional + // finger that move/start/end, dispatched directly to whoever is the + // current responder at that moment, until the responder is "released". + // + // These multiple individual change touch events are are always bookended + // by `onResponderGrant`, and one of + // (`onResponderRelease/onResponderTerminate`). + var isResponderTouchStart = responderInst && isStartish(topLevelType); + var isResponderTouchMove = responderInst && isMoveish(topLevelType); + var isResponderTouchEnd = responderInst && isEndish(topLevelType); + var incrementalTouch = isResponderTouchStart + ? eventTypes.responderStart + : isResponderTouchMove + ? eventTypes.responderMove + : isResponderTouchEnd + ? eventTypes.responderEnd + : null; + + if (incrementalTouch) { + var gesture = ResponderSyntheticEvent.getPooled( + incrementalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(gesture); + extracted = accumulate(extracted, gesture); + } + + var isResponderTerminate = + responderInst && topLevelType === TOP_TOUCH_CANCEL; + var isResponderRelease = + responderInst && + !isResponderTerminate && + isEndish(topLevelType) && + noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate + ? eventTypes.responderTerminate + : isResponderRelease + ? eventTypes.responderRelease + : null; + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled( + finalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + return extracted; + }, + + GlobalResponderHandler: null, + + injection: { + /** + * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler + * Object that handles any change in responder. Use this to inject + * integration with an existing touch handling system etc. + */ + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } +}; + +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + +var ReactNativeBridgeEventPlugin = { + eventTypes: eventTypes$1, + + /** + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (targetInst == null) { + // Probably a node belonging to another renderer's tree. + return null; + } + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; + (function() { + if (!(bubbleDispatchConfig || directDispatchConfig)) { + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + } + })(); + var event = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) { + accumulateTwoPhaseDispatches(event); + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; + } + return event; + } +}; + +var ReactNativeEventPluginOrder = [ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]; + +/** + * Make sure essential globals are available and are patched correctly. Please don't remove this + * line. Bundles created by react-packager `require` it before executing any application code. This + * ensures it exists in the dependency graph and can be `require`d. + * TODO: require this in packager, not in React #10932517 + */ +// Module provided by RN: +/** + * Inject module for resolving DOM hierarchy and plugin ordering. + */ +injection.injectEventPluginOrder(ReactNativeEventPluginOrder); + +/** + * Some important event plugins included by default (without having to require + * them). + */ +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); + +function getInstanceFromInstance(instanceHandle) { + return instanceHandle; +} + +function getTagFromInstance(inst) { + var tag = inst.stateNode.canonical._nativeTag; + (function() { + if (!tag) { + throw ReactError("All native instances should have a tag."); + } + })(); + return tag; +} + +function getFiberCurrentPropsFromNode$1(inst) { + return inst.canonical.currentProps; +} + +// Module provided by RN: +var ReactFabricGlobalResponderHandler = { + onChange: function(from, to, blockNativeResponder) { + if (to !== null) { + var tag = to.stateNode.canonical._nativeTag; + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); + } else { + ReactNativePrivateInterface.UIManager.clearJSResponder(); + } + } +}; + +setComponentTree( + getFiberCurrentPropsFromNode$1, + getInstanceFromInstance, + getTagFromInstance +); + +ResponderEventPlugin.injection.injectGlobalResponderHandler( + ReactFabricGlobalResponderHandler +); + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ + +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + +function get(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +// Prevent newer renderers from RTE when used with older react package versions. +// Current owner and dispatcher used to share the same ref, +// but PR #14548 split them out to better support the react-debug-tools package. +if (!ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher")) { + ReactSharedInternals.ReactCurrentDispatcher = { + current: null + }; +} + +// The Symbol used to tag the ReactElement-like types. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var hasSymbol = typeof Symbol === "function" && Symbol.for; + +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 0xeac7; +var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 0xeaca; +var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 0xeacb; +var REACT_STRICT_MODE_TYPE = hasSymbol + ? Symbol.for("react.strict_mode") + : 0xeacc; +var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 0xead2; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 0xeace; + +var REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol.for("react.forward_ref") + : 0xead0; +var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 0xead1; +var REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 0xead3; +var REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 0xead4; +var REACT_EVENT_COMPONENT_TYPE = hasSymbol + ? Symbol.for("react.event_component") + : 0xead5; +var REACT_EVENT_TARGET_TYPE = hasSymbol + ? Symbol.for("react.event_target") + : 0xead6; + +// React event targets +var REACT_EVENT_TARGET_TOUCH_HIT = hasSymbol + ? Symbol.for("react.event_target.touch_hit") + : 0xead7; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = "@@iterator"; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== "object") { + return null; + } + var maybeIterator = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === "function") { + return maybeIterator; + } + return null; +} + +var Pending = 0; +var Resolved = 1; +var Rejected = 2; + +function refineResolvedLazyComponent(lazyComponent) { + return lazyComponent._status === Resolved ? lazyComponent._result : null; +} + +// Re-export dynamic flags from the fbsource version. +var _require = require("../shims/ReactFeatureFlags"); + +var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; + +var enableUserTimingAPI = true; +var enableProfilerTimer = true; +var enableSchedulerTracing = true; +var enableSuspenseServerRenderer = false; + +var debugRenderPhaseSideEffectsForStrictMode = true; + +var disableYielding = false; + +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; +var warnAboutDeprecatedLifecycles = true; +var warnAboutDeprecatedSetNativeProps = true; +var enableEventAPI = false; + +// Only used in www builds. + +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ""; + return ( + outerType.displayName || + (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName) + ); +} + +function getComponentName(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + { + if (typeof type.tag === "number") { + warningWithoutStack$1( + false, + "Received an unexpected object in getComponentName(). " + + "This is likely a bug in React. Please file an issue." + ); + } + } + if (typeof type === "function") { + return type.displayName || type.name || null; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, "ForwardRef"); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: { + var thenable = type; + var resolvedThenable = refineResolvedLazyComponent(thenable); + if (resolvedThenable) { + return getComponentName(resolvedThenable); + } + break; + } + case REACT_EVENT_COMPONENT_TYPE: { + if (enableEventAPI) { + var eventComponent = type; + var displayName = eventComponent.displayName; + if (displayName !== undefined) { + return displayName; + } + } + break; + } + case REACT_EVENT_TARGET_TYPE: { + if (enableEventAPI) { + var eventTarget = type; + if (eventTarget.type === REACT_EVENT_TARGET_TOUCH_HIT) { + return "TouchHitTarget"; + } + var _displayName = eventTarget.displayName; + if (_displayName !== undefined) { + return _displayName; + } + } + } + } + } + return null; +} + +// Don't change these two values. They're used by React Dev Tools. +var NoEffect = /* */ 0; +var PerformedWork = /* */ 1; + +// You can change the rest (and add more). +var Placement = /* */ 2; +var Update = /* */ 4; +var PlacementAndUpdate = /* */ 6; +var Deletion = /* */ 8; +var ContentReset = /* */ 16; +var Callback = /* */ 32; +var DidCapture = /* */ 64; +var Ref = /* */ 128; +var Snapshot = /* */ 256; +var Passive = /* */ 512; + +// Passive & Update & Callback & Ref & Snapshot +var LifecycleEffectMask = /* */ 932; + +// Union of all host effects +var HostEffectMask = /* */ 1023; + +var Incomplete = /* */ 1024; +var ShouldCapture = /* */ 2048; + +var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; + +var MOUNTING = 1; +var MOUNTED = 2; +var UNMOUNTED = 3; + +function isFiberMountedImpl(fiber) { + var node = fiber; + if (!fiber.alternate) { + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + while (node.return) { + node = node.return; + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + } + } else { + while (node.return) { + node = node.return; + } + } + if (node.tag === HostRoot) { + // TODO: Check if this was a nested HostRoot when used with + // renderContainerIntoSubtree. + return MOUNTED; + } + // If we didn't hit the root, that means that we're in an disconnected tree + // that has been unmounted. + return UNMOUNTED; +} + +function isFiberMounted(fiber) { + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function isMounted(component) { + { + var owner = ReactCurrentOwner$1.current; + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + !instance._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing isMounted inside its render() function. " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(ownerFiber.type) || "A component" + ) + : void 0; + instance._warnedAboutRefsInRender = true; + } + } + + var fiber = get(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + (function() { + if (!(isFiberMountedImpl(fiber) === MOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); +} + +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var state = isFiberMountedImpl(fiber); + (function() { + if (!(state !== UNMOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (state === MOUNTING) { + return null; + } + return fiber; + } + // If we have two possible branches, we'll walk backwards up to the root + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. + var a = fiber; + var b = alternate; + while (true) { + var parentA = a.return; + if (parentA === null) { + // We're at the root. + break; + } + var parentB = parentA.alternate; + if (parentB === null) { + // There is no alternate. This is an unusual case. Currently, it only + // happens when a Suspense component is hidden. An extra fragment fiber + // is inserted in between the Suspense fiber and its children. Skip + // over this extra fragment fiber and proceed to the next parent. + var nextParent = parentA.return; + if (nextParent !== null) { + a = b = nextParent; + continue; + } + // If there's no parent, we're at the root. + break; + } + + // If both copies of the parent fiber point to the same child, we can + // assume that the child is current. This happens when we bailout on low + // priority: the bailed out fiber's child reuses the current child. + if (parentA.child === parentB.child) { + var child = parentA.child; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } + child = child.sibling; + } + // We should never have an alternate for any mounting node. So the only + // way this could possibly happen is if this was unmounted, if at all. + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } + + if (a.return !== b.return) { + // The return pointer of A and the return pointer of B point to different + // fibers. We assume that return pointers never criss-cross, so A must + // belong to the child set of A.return, and B must belong to the child + // set of B.return. + a = parentA; + b = parentB; + } else { + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set + var didFindChild = false; + var _child = parentA.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + (function() { + if (!didFindChild) { + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + })(); + } + } + + (function() { + if (!(a.alternate === b)) { + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. + (function() { + if (!(a.tag === HostRoot)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } + // Otherwise B has to be current branch. + return alternate; +} + +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + if (!currentParent) { + return null; + } + + // Next we'll drill down this component to find the first HostComponent/Text. + var node = currentParent; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + return node; + } else if (node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === currentParent) { + return null; + } + while (!node.sibling) { + if (!node.return || node.return === currentParent) { + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + // Flow needs the return null here, but ESLint complains about it. + // eslint-disable-next-line no-unreachable + return null; +} + +/** + * In the future, we should cleanup callbacks by cancelling them instead of + * using this. + */ +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if (!callback) { + return undefined; + } + // This protects against createClass() components. + // We don't know if there is code depending on it. + // We intentionally don't use isMounted() because even accessing + // isMounted property on a React ES6 class will trigger a warning. + if (typeof context.__isMounted === "boolean") { + if (!context.__isMounted) { + return undefined; + } + } + + // FIXME: there used to be other branches that protected + // against unmounted host components. But RN host components don't + // define isMounted() anymore, so those checks didn't do anything. + + // They caused false positive warning noise so we removed them: + // https://github.com/facebook/react-native/issues/18868#issuecomment-413579095 + + // However, this means that the callback is NOT guaranteed to be safe + // for host components. The solution we should implement is to make + // UIManager.measure() and similar calls truly cancelable. Then we + // can change our own code calling them to cancel when something unmounts. + + return callback.apply(context, arguments); + }; +} + +function throwOnStylesProp(component, props) { + if (props.styles !== undefined) { + var owner = component._owner || null; + var name = component.constructor.displayName; + var msg = + "`styles` is not a supported property of `" + + name + + "`, did " + + "you mean `style` (singular)?"; + if (owner && owner.constructor && owner.constructor.displayName) { + msg += + "\n\nCheck the `" + + owner.constructor.displayName + + "` parent " + + " component."; + } + throw new Error(msg); + } +} + +function warnForStyleProps(props, validAttributes) { + for (var key in validAttributes.style) { + if (!(validAttributes[key] || props[key] === undefined)) { + console.error( + "You are setting the style `{ " + + key + + ": ... }` as a prop. You " + + "should nest it in a style object. " + + "E.g. `{ style: { " + + key + + ": ... } }`" + ); + } + } +} + +// Modules provided by RN: +var emptyObject = {}; + +/** + * Create a payload that contains all the updates between two sets of props. + * + * These helpers are all encapsulated into a single module, because they use + * mutation as a performance optimization which leads to subtle shared + * dependencies between the code paths. To avoid this mutable state leaking + * across modules, I've kept them isolated to this module. + */ + +// Tracks removed keys +var removedKeys = null; +var removedKeyCount = 0; + +function defaultDiffer(prevProp, nextProp) { + if (typeof nextProp !== "object" || nextProp === null) { + // Scalars have already been checked for equality + return true; + } else { + // For objects and arrays, the default diffing algorithm is a deep compare + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); + } +} + +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) { + var i = node.length; + while (i-- && removedKeyCount > 0) { + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + } + } else if (node && removedKeyCount > 0) { + var obj = node; + for (var propKey in removedKeys) { + if (!removedKeys[propKey]) { + continue; + } + var nextProp = obj[propKey]; + if (nextProp === undefined) { + continue; + } + + var attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (typeof nextProp === "function") { + nextProp = true; + } + if (typeof nextProp === "undefined") { + nextProp = null; + } + + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + removedKeys[propKey] = false; + removedKeyCount--; + } + } +} + +function diffNestedArrayProperty( + updatePayload, + prevArray, + nextArray, + validAttributes +) { + var minLength = + prevArray.length < nextArray.length ? prevArray.length : nextArray.length; + var i = void 0; + for (i = 0; i < minLength; i++) { + // Diff any items in the array in the forward direction. Repeated keys + // will be overwritten by later values. + updatePayload = diffNestedProperty( + updatePayload, + prevArray[i], + nextArray[i], + validAttributes + ); + } + for (; i < prevArray.length; i++) { + // Clear out all remaining properties. + updatePayload = clearNestedProperty( + updatePayload, + prevArray[i], + validAttributes + ); + } + for (; i < nextArray.length; i++) { + // Add all remaining properties. + updatePayload = addNestedProperty( + updatePayload, + nextArray[i], + validAttributes + ); + } + return updatePayload; +} + +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) { + // If no properties have been added, then we can bail out quickly on object + // equality. + return updatePayload; + } + + if (!prevProp || !nextProp) { + if (nextProp) { + return addNestedProperty(updatePayload, nextProp, validAttributes); + } + if (prevProp) { + return clearNestedProperty(updatePayload, prevProp, validAttributes); + } + return updatePayload; + } + + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { + // Both are leaves, we can diff the leaves. + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + } + + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + // Both are arrays, we can diff the arrays. + return diffNestedArrayProperty( + updatePayload, + prevProp, + nextProp, + validAttributes + ); + } + + if (Array.isArray(prevProp)) { + return diffProperties( + updatePayload, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(prevProp), + // $FlowFixMe - We know that this isn't an array because of above flow. + nextProp, + validAttributes + ); + } + + return diffProperties( + updatePayload, + prevProp, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} + +/** + * addNestedProperty takes a single set of props and valid attribute + * attribute configurations. It processes each prop and adds it to the + * updatePayload. + */ +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) { + return updatePayload; + } + + if (!Array.isArray(nextProp)) { + // Add each property of the leaf. + return addProperties(updatePayload, nextProp, validAttributes); + } + + for (var i = 0; i < nextProp.length; i++) { + // Add all the properties of the array. + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + } + + return updatePayload; +} + +/** + * clearNestedProperty takes a single set of props and valid attributes. It + * adds a null sentinel to the updatePayload, for each prop key. + */ +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) { + return updatePayload; + } + + if (!Array.isArray(prevProp)) { + // Add each property of the leaf. + return clearProperties(updatePayload, prevProp, validAttributes); + } + + for (var i = 0; i < prevProp.length; i++) { + // Add all the properties of the array. + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + } + return updatePayload; +} + +/** + * diffProperties takes two sets of props and a set of valid attributes + * and write to updatePayload the values that changed or were deleted. + * If no updatePayload is provided, a new one is created and returned if + * anything changed. + */ +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig = void 0; + var nextProp = void 0; + var prevProp = void 0; + + for (var propKey in nextProps) { + attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + prevProp = prevProps[propKey]; + nextProp = nextProps[propKey]; + + // functions are converted to booleans as markers that the associated + // events should be sent from native. + if (typeof nextProp === "function") { + nextProp = true; + // If nextProp is not a function, then don't bother changing prevProp + // since nextProp will win and go into the updatePayload regardless. + if (typeof prevProp === "function") { + prevProp = true; + } + } + + // An explicit value of undefined is treated as a null because it overrides + // any other preceding value. + if (typeof nextProp === "undefined") { + nextProp = null; + if (typeof prevProp === "undefined") { + prevProp = null; + } + } + + if (removedKeys) { + removedKeys[propKey] = false; + } + + if (updatePayload && updatePayload[propKey] !== undefined) { + // Something else already triggered an update to this key because another + // value diffed. Since we're now later in the nested arrays our value is + // more important so we need to calculate it and override the existing + // value. It doesn't matter if nothing changed, we'll set it anyway. + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + continue; + } + + if (prevProp === nextProp) { + continue; // nothing changed + } + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + if (defaultDiffer(prevProp, nextProp)) { + // a normal leaf has changed + (updatePayload || (updatePayload = {}))[propKey] = nextProp; + } + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var shouldUpdate = + prevProp === undefined || + (typeof attributeConfig.diff === "function" + ? attributeConfig.diff(prevProp, nextProp) + : defaultDiffer(prevProp, nextProp)); + if (shouldUpdate) { + var _nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + (updatePayload || (updatePayload = {}))[propKey] = _nextValue; + } + } else { + // default: fallthrough case when nested properties are defined + removedKeys = null; + removedKeyCount = 0; + // We think that attributeConfig is not CustomAttributeConfiguration at + // this point so we assume it must be AttributeConfiguration. + updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + ); + if (removedKeyCount > 0 && updatePayload) { + restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ); + removedKeys = null; + } + } + } + + // Also iterate through all the previous props to catch any that have been + // removed and make sure native gets the signal so it can reset them to the + // default. + for (var _propKey in prevProps) { + if (nextProps[_propKey] !== undefined) { + continue; // we've already covered this key in the previous pass + } + attributeConfig = validAttributes[_propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (updatePayload && updatePayload[_propKey] !== undefined) { + // This was already updated to a diff result earlier. + continue; + } + + prevProp = prevProps[_propKey]; + if (prevProp === undefined) { + continue; // was already empty anyway + } + // Pattern match on: attributeConfig + if ( + typeof attributeConfig !== "object" || + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration | !Object + // Flag the leaf property for removal by sending a sentinel. + (updatePayload || (updatePayload = {}))[_propKey] = null; + if (!removedKeys) { + removedKeys = {}; + } + if (!removedKeys[_propKey]) { + removedKeys[_propKey] = true; + removedKeyCount++; + } + } else { + // default: + // This is a nested attribute configuration where all the properties + // were removed so we need to go through and clear out all of them. + updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ); + } + } + return updatePayload; +} + +/** + * addProperties adds all the valid props to the payload after being processed. + */ +function addProperties(updatePayload, props, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, emptyObject, props, validAttributes); +} + +/** + * clearProperties clears all the previous props by adding a null sentinel + * to the payload for each valid key. + */ +function clearProperties(updatePayload, prevProps, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, prevProps, emptyObject, validAttributes); +} + +function create(props, validAttributes) { + return addProperties( + null, // updatePayload + props, + validAttributes + ); +} + +function diff(prevProps, nextProps, validAttributes) { + return diffProperties( + null, // updatePayload + prevProps, + nextProps, + validAttributes + ); +} + +// Use to restore controlled state after a change event has fired. + +var restoreImpl = null; +var restoreTarget = null; +var restoreQueue = null; + +function restoreStateOfTarget(target) { + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here + var internalInstance = getInstanceFromNode(target); + if (!internalInstance) { + // Unmounted + return; + } + (function() { + if (!(typeof restoreImpl === "function")) { + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + restoreImpl(internalInstance.stateNode, internalInstance.type, props); +} + +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} + +function restoreStateIfNeeded() { + if (!restoreTarget) { + return; + } + var target = restoreTarget; + var queuedTargets = restoreQueue; + restoreTarget = null; + restoreQueue = null; + + restoreStateOfTarget(target); + if (queuedTargets) { + for (var i = 0; i < queuedTargets.length; i++) { + restoreStateOfTarget(queuedTargets[i]); + } + } +} + +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. + +// Defaults +var _batchedUpdatesImpl = function(fn, bookkeeping) { + return fn(bookkeeping); +}; +var _flushInteractiveUpdatesImpl = function() {}; + +var isBatching = false; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(bookkeeping); + } + isBatching = true; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdatesImpl(); + restoreStateIfNeeded(); + } + } +} + +function setBatchingImplementation( + batchedUpdatesImpl, + interactiveUpdatesImpl, + flushInteractiveUpdatesImpl +) { + _batchedUpdatesImpl = batchedUpdatesImpl; + _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl; +} + +function dispatchEvent(target, topLevelType, nativeEvent) { + var targetFiber = target; + batchedUpdates(function() { + runExtractedPluginEventsInBatch( + topLevelType, + targetFiber, + nativeEvent, + nativeEvent.target + ); + }); + // React Native doesn't use ReactControlledComponent but if it did, here's + // where it would do it. +} + +// Renderers that don't support mutation +// can re-export everything from this module. + +function shim() { + (function() { + { + throw ReactError( + "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Mutation (when unsupported) +var supportsMutation = false; +var appendChild = shim; +var appendChildToContainer = shim; +var commitTextUpdate = shim; +var commitMount = shim; +var commitUpdate = shim; +var insertBefore = shim; +var insertInContainerBefore = shim; +var removeChild = shim; +var removeChildFromContainer = shim; +var resetTextContent = shim; +var hideInstance = shim; +var hideTextInstance = shim; +var unhideInstance = shim; +var unhideTextInstance = shim; + +// Renderers that don't support hydration +// can re-export everything from this module. + +function shim$1() { + (function() { + { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Hydration (when unsupported) + +var supportsHydration = false; +var canHydrateInstance = shim$1; +var canHydrateTextInstance = shim$1; +var canHydrateSuspenseInstance = shim$1; +var isSuspenseInstancePending = shim$1; +var isSuspenseInstanceFallback = shim$1; +var registerSuspenseInstanceRetry = shim$1; +var getNextHydratableSibling = shim$1; +var getFirstHydratableChild = shim$1; +var hydrateInstance = shim$1; +var hydrateTextInstance = shim$1; +var getNextHydratableInstanceAfterSuspenseInstance = shim$1; +var clearSuspenseBoundary = shim$1; +var clearSuspenseBoundaryFromContainer = shim$1; +var didNotMatchHydratedContainerTextInstance = shim$1; +var didNotMatchHydratedTextInstance = shim$1; +var didNotHydrateContainerInstance = shim$1; +var didNotHydrateInstance = shim$1; +var didNotFindHydratableContainerInstance = shim$1; +var didNotFindHydratableContainerTextInstance = shim$1; +var didNotFindHydratableContainerSuspenseInstance = shim$1; +var didNotFindHydratableInstance = shim$1; +var didNotFindHydratableTextInstance = shim$1; +var didNotFindHydratableSuspenseInstance = shim$1; + +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +// Modules provided by RN: +var _nativeFabricUIManage = nativeFabricUIManager; +var createNode = _nativeFabricUIManage.createNode; +var cloneNode = _nativeFabricUIManage.cloneNode; +var cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren; +var cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps; +var cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps; +var createChildNodeSet = _nativeFabricUIManage.createChildSet; +var appendChildNode = _nativeFabricUIManage.appendChild; +var appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet; +var completeRoot = _nativeFabricUIManage.completeRoot; +var registerEventHandler = _nativeFabricUIManage.registerEventHandler; +var fabricMeasure = _nativeFabricUIManage.measure; +var fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow; +var fabricMeasureLayout = _nativeFabricUIManage.measureLayout; +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; + +// Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. +// This means that they never overlap. + +var nextReactTag = 2; + +// TODO: Remove this conditional once all changes have propagated. +if (registerEventHandler) { + /** + * Register the event emitter with the native bridge + */ + registerEventHandler(dispatchEvent); +} + +/** + * This is used for refs on host components. + */ + +var ReactFabricHostComponent = (function() { + function ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ) { + _classCallCheck(this, ReactFabricHostComponent); + + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + this._internalInstanceHandle = internalInstanceHandle; + } + + ReactFabricHostComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + + ReactFabricHostComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + + ReactFabricHostComponent.prototype.measure = function measure(callback) { + fabricMeasure( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + fabricMeasureInWindow( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactFabricHostComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + if ( + typeof relativeToNativeNode === "number" || + !(relativeToNativeNode instanceof ReactFabricHostComponent) + ) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a ref to a native component." + ); + + return; + } + + fabricMeasureLayout( + this._internalInstanceHandle.stateNode.node, + relativeToNativeNode._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + + ReactFabricHostComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + + return; + }; + + return ReactFabricHostComponent; +})(); + +function appendInitialChild(parentInstance, child) { + appendChildNode(parentInstance.node, child.node); +} + +function createInstance( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + var tag = nextReactTag; + nextReactTag += 2; + + var viewConfig = getViewConfigForType(type); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); + } + } + } + + var updatePayload = create(props, viewConfig.validAttributes); + + var node = createNode( + tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload, // props + internalInstanceHandle // internalInstanceHandle + ); + + var component = new ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ); + + return { + node: node, + canonical: component + }; +} + +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + (function() { + if (!hostContext.isInAParentText) { + throw ReactError( + "Text strings must be rendered within a component." + ); + } + })(); + + var tag = nextReactTag; + nextReactTag += 2; + + var node = createNode( + tag, // reactTag + "RCTRawText", // viewName + rootContainerInstance, // rootTag + { text: text }, // props + internalInstanceHandle // instance handle + ); + + return { + node: node + }; +} + +function finalizeInitialChildren( + parentInstance, + type, + props, + rootContainerInstance, + hostContext +) { + return false; +} + +function getRootHostContext(rootContainerInstance) { + return { isInAParentText: false }; +} + +function getChildHostContext(parentHostContext, type, rootContainerInstance) { + var prevIsInAParentText = parentHostContext.isInAParentText; + var isInAParentText = + type === "AndroidTextInput" || // Android + type === "RCTMultilineTextInputView" || // iOS + type === "RCTSinglelineTextInputView" || // iOS + type === "RCTText" || + type === "RCTVirtualText"; + + if (prevIsInAParentText !== isInAParentText) { + return { isInAParentText: isInAParentText }; + } else { + return parentHostContext; + } +} + +function getChildHostContextForEventComponent(parentHostContext) { + // TODO: add getChildHostContextForEventComponent implementation + return parentHostContext; +} + +function getChildHostContextForEventTarget(parentHostContext, type) { + // TODO: add getChildHostContextForEventTarget implementation + return parentHostContext; +} + +function getPublicInstance(instance) { + return instance.canonical; +} + +function prepareForCommit(containerInfo) { + // Noop +} + +function prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + hostContext +) { + var viewConfig = instance.canonical.viewConfig; + var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); + // TODO: If the event handlers have changed, we need to update the current props + // in the commit phase but there is no host config hook to do it yet. + // So instead we hack it by updating it in the render phase. + instance.canonical.currentProps = newProps; + return updatePayload; +} + +function resetAfterCommit(containerInfo) { + // Noop +} + +function shouldDeprioritizeSubtree(type, props) { + return false; +} + +function shouldSetTextContent(type, props) { + // TODO (bvaughn) Revisit this decision. + // Always returning false simplifies the createInstance() implementation, + // But creates an additional child Fiber for raw text children. + // No additional native views are created though. + // It's not clear to me which is better so I'm deferring for now. + // More context @ github.com/facebook/react/pull/8560#discussion_r92111303 + return false; +} + +// The Fabric renderer is secondary to the existing React Native renderer. +var isPrimaryRenderer = false; + +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; + +// ------------------- +// Persistence +// ------------------- + +var supportsPersistence = true; + +function cloneInstance( + instance, + updatePayload, + type, + oldProps, + newProps, + internalInstanceHandle, + keepChildren, + recyclableInstance +) { + var node = instance.node; + var clone = void 0; + if (keepChildren) { + if (updatePayload !== null) { + clone = cloneNodeWithNewProps(node, updatePayload); + } else { + clone = cloneNode(node); + } + } else { + if (updatePayload !== null) { + clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); + } else { + clone = cloneNodeWithNewChildren(node); + } + } + return { + node: clone, + canonical: instance.canonical + }; +} + +function cloneHiddenInstance(instance, type, props, internalInstanceHandle) { + var viewConfig = instance.canonical.viewConfig; + var node = instance.node; + var updatePayload = create( + { style: { display: "none" } }, + viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, updatePayload), + canonical: instance.canonical + }; +} + +function cloneHiddenTextInstance(instance, text, internalInstanceHandle) { + throw new Error("Not yet implemented."); +} + +function createContainerChildSet(container) { + return createChildNodeSet(container); +} + +function appendChildToContainerChildSet(childSet, child) { + appendChildNodeToSet(childSet, child.node); +} + +function finalizeContainerChildren(container, newChildren) { + completeRoot(container, newChildren); +} + +function mountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function updateEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function unmountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function getEventTargetChildElement(type, props) { + throw new Error("Not yet implemented."); +} + +function handleEventTarget( + type, + props, + rootContainerInstance, + internalInstanceHandle +) { + throw new Error("Not yet implemented."); +} + +function commitEventTarget(type, props, instance, parentInstance) { + throw new Error("Not yet implemented."); +} + +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; + +var describeComponentFrame = function(name, source, ownerName) { + var sourceInfo = ""; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ""); + { + // In DEV, include code for a common special case: + // prefer "folder/index.js" instead of just "index.js". + if (/^index\./.test(fileName)) { + var match = path.match(BEFORE_SLASH_RE); + if (match) { + var pathBeforeSlash = match[1]; + if (pathBeforeSlash) { + var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); + fileName = folderName + "/" + fileName; + } + } + } + } + sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; + } else if (ownerName) { + sourceInfo = " (created by " + ownerName + ")"; + } + return "\n in " + (name || "Unknown") + sourceInfo; +}; + +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + +function describeFiber(fiber) { + switch (fiber.tag) { + case HostRoot: + case HostPortal: + case HostText: + case Fragment: + case ContextProvider: + case ContextConsumer: + return ""; + default: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber.type); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner.type); + } + return describeComponentFrame(name, source, ownerName); + } +} + +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + node = node.return; + } while (node); + return info; +} + +var current = null; +var phase = null; + +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; + } + var owner = current._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner.type); + } + } + return null; +} + +function getCurrentFiberStackInDev() { + { + if (current === null) { + return ""; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackByFiberInDevAndProd(current); + } + return ""; +} + +function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + phase = null; + } +} + +function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackInDev; + current = fiber; + phase = null; + } +} + +function setCurrentPhase(lifeCyclePhase) { + { + phase = lifeCyclePhase; + } +} + +// Prefix measurements so that it's possible to filter them. +// Longer prefixes are hard to read in DevTools. +var reactEmoji = "\u269B"; +var warningEmoji = "\u26D4"; +var supportsUserTiming = + typeof performance !== "undefined" && + typeof performance.mark === "function" && + typeof performance.clearMarks === "function" && + typeof performance.measure === "function" && + typeof performance.clearMeasures === "function"; + +// Keep track of current fiber so that we know the path to unwind on pause. +// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? +var currentFiber = null; +// If we're in the middle of user code, which fiber and method is it? +// Reusing `currentFiber` would be confusing for this because user code fiber +// can change during commit phase too, but we don't need to unwind it (since +// lifecycles in the commit phase don't resemble a tree). +var currentPhase = null; +var currentPhaseFiber = null; +// Did lifecycle hook schedule an update? This is often a performance problem, +// so we will keep track of it, and include it in the report. +// Track commits caused by cascading updates. +var isCommitting = false; +var hasScheduledUpdateInCurrentCommit = false; +var hasScheduledUpdateInCurrentPhase = false; +var commitCountInCurrentWorkLoop = 0; +var effectCountInCurrentCommit = 0; +var isWaitingForCallback = false; +// During commits, we only show a measurement once per method name +// to avoid stretch the commit phase with measurement overhead. +var labelsInCurrentCommit = new Set(); + +var formatMarkName = function(markName) { + return reactEmoji + " " + markName; +}; + +var formatLabel = function(label, warning) { + var prefix = warning ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning ? " Warning: " + warning : ""; + return "" + prefix + label + suffix; +}; + +var beginMark = function(markName) { + performance.mark(formatMarkName(markName)); +}; + +var clearMark = function(markName) { + performance.clearMarks(formatMarkName(markName)); +}; + +var endMark = function(label, markName, warning) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning); + try { + performance.measure(formattedLabel, formattedMarkName); + } catch (err) {} + // If previous mark was missing for some reason, this will throw. + // This could only happen if React crashed in an unexpected place earlier. + // Don't pile on with more errors. + + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); +}; + +var getFiberMarkName = function(label, debugID) { + return label + " (#" + debugID + ")"; +}; + +var getFiberLabel = function(componentName, isMounted, phase) { + if (phase === null) { + // These are composite component total time measurements. + return componentName + " [" + (isMounted ? "update" : "mount") + "]"; + } else { + // Composite component methods. + return componentName + "." + phase; + } +}; + +var beginFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + + if (isCommitting && labelsInCurrentCommit.has(label)) { + // During the commit phase, we don't show duplicate labels because + // there is a fixed overhead for every measurement, and we don't + // want to stretch the commit phase beyond necessary. + return false; + } + labelsInCurrentCommit.add(label); + + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; +}; + +var clearFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + clearMark(markName); +}; + +var endFiberMark = function(fiber, phase, warning) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + endMark(label, markName, warning); +}; + +var shouldIgnoreFiber = function(fiber) { + // Host components should be skipped in the timeline. + // We could check typeof fiber.type, but does this work with RN? + switch (fiber.tag) { + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case Fragment: + case ContextProvider: + case ContextConsumer: + case Mode: + return true; + default: + return false; + } +}; + +var clearPendingPhaseMeasurement = function() { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; + +var pauseTimers = function() { + // Stops all currently active measurements so that they can be resumed + // if we continue in a later deferred loop from the same unit of work. + var fiber = currentFiber; + while (fiber) { + if (fiber._debugIsCurrentlyTiming) { + endFiberMark(fiber, null, null); + } + fiber = fiber.return; + } +}; + +var resumeTimersRecursively = function(fiber) { + if (fiber.return !== null) { + resumeTimersRecursively(fiber.return); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } +}; + +var resumeTimers = function() { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; + +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} + +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; + } + if ( + currentPhase !== null && + currentPhase !== "componentWillMount" && + currentPhase !== "componentWillReceiveProps" + ) { + hasScheduledUpdateInCurrentPhase = true; + } + } +} + +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark("(Waiting for async callback...)"); + } + } +} + +function stopRequestCallbackTimer(didExpire) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning = didExpire + ? "Update expired; will flush synchronously" + : null; + endMark( + "(Waiting for async callback...)", + "(Waiting for async callback...)", + warning + ); + } + } +} + +function startWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, this is the fiber to unwind from. + currentFiber = fiber; + if (!beginFiberMark(fiber, null)) { + return; + } + fiber._debugIsCurrentlyTiming = true; + } +} + +function cancelWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // Remember we shouldn't complete measurement for this fiber. + // Otherwise flamechart will be deep even for small updates. + fiber._debugIsCurrentlyTiming = false; + clearFiberMark(fiber, null); + } +} + +function stopWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + endFiberMark(fiber, null, null); + } +} + +function stopFailedWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + var warning = + fiber.tag === SuspenseComponent || + fiber.tag === DehydratedSuspenseComponent + ? "Rendering was suspended" + : "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning); + } +} + +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; + } + currentPhaseFiber = fiber; + currentPhase = phase; + } +} + +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + if (currentPhase !== null && currentPhaseFiber !== null) { + var warning = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning); + } + currentPhase = null; + currentPhaseFiber = null; + } +} + +function startWorkLoopTimer(nextUnitOfWork) { + if (enableUserTimingAPI) { + currentFiber = nextUnitOfWork; + if (!supportsUserTiming) { + return; + } + commitCountInCurrentWorkLoop = 0; + // This is top level call. + // Any other measurements are performed within. + beginMark("(React Tree Reconciliation)"); + // Resume any measurements that were in progress during the last loop. + resumeTimers(); + } +} + +function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var warning = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy.type) || "Unknown"; + warning = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning = "There were cascading updates"; + } + commitCountInCurrentWorkLoop = 0; + var label = didCompleteRoot + ? "(React Tree Reconciliation: Completed Root)" + : "(React Tree Reconciliation: Yielded)"; + // Pause any measurements until the next loop. + pauseTimers(); + endMark(label, "(React Tree Reconciliation)", warning); + } +} + +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark("(Committing Changes)"); + } +} + +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + + var warning = null; + if (hasScheduledUpdateInCurrentCommit) { + warning = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning = "Caused by a cascading update in earlier commit"; + } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark("(Committing Changes)", "(Committing Changes)", warning); + } +} + +function startCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Snapshot Effects)"); + } +} + +function stopCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Snapshot Effects: " + count + " Total)", + "(Committing Snapshot Effects)", + null + ); + } +} + +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Host Effects)"); + } +} + +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Host Effects: " + count + " Total)", + "(Committing Host Effects)", + null + ); + } +} + +function startCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Calling Lifecycle Methods)"); + } +} + +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Calling Lifecycle Methods: " + count + " Total)", + "(Calling Lifecycle Methods)", + null + ); + } +} + +var valueStack = []; + +var fiberStack = void 0; + +{ + fiberStack = []; +} + +var index = -1; + +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} + +function pop(cursor, fiber) { + if (index < 0) { + { + warningWithoutStack$1(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warningWithoutStack$1(false, "Unexpected Fiber popped."); + } + } + + cursor.current = valueStack[index]; + + valueStack[index] = null; + + { + fiberStack[index] = null; + } + + index--; +} + +function push(cursor, value, fiber) { + index++; + + valueStack[index] = cursor.current; + + { + fiberStack[index] = fiber; + } + + cursor.current = value; +} + +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var emptyContextObject = {}; +{ + Object.freeze(emptyContextObject); +} + +// A cursor to the current merged context object on the stack. +var contextStackCursor = createCursor(emptyContextObject); +// A cursor to a boolean indicating whether the context has changed. +var didPerformWorkStackCursor = createCursor(false); +// Keep track of the previous context object that was on the stack. +// We use this to get access to the parent context after we have already +// pushed the next context provider, and now need to merge their contexts. +var previousContext = emptyContextObject; + +function getUnmaskedContext( + workInProgress, + Component, + didPushOwnContextIfProvider +) { + if (didPushOwnContextIfProvider && isContextProvider(Component)) { + // If the fiber is a context provider itself, when we read its context + // we may have already pushed its own child context on the stack. A context + // provider should not "see" its own child context. Therefore we read the + // previous (parent) context instead for a context provider. + return previousContext; + } + return contextStackCursor.current; +} + +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; +} + +function getMaskedContext(workInProgress, unmaskedContext) { + var type = workInProgress.type; + var contextTypes = type.contextTypes; + if (!contextTypes) { + return emptyContextObject; + } + + // Avoid recreating masked context unless unmasked context has changed. + // Failing to do this will result in unnecessary calls to componentWillReceiveProps. + // This may trigger infinite loops if componentWillReceiveProps calls setState. + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) { + return instance.__reactInternalMemoizedMaskedChildContext; + } + + var context = {}; + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } + + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + getCurrentFiberStackInDev + ); + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // Context is created before the class component is instantiated so check for instance. + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return context; +} + +function hasContextChanged() { + return didPerformWorkStackCursor.current; +} + +function isContextProvider(type) { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; +} + +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function pushTopLevelContextObject(fiber, context, didChange) { + (function() { + if (!(contextStackCursor.current === emptyContextObject)) { + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} + +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = type.childContextTypes; + + // TODO (bvaughn) Replace this behavior with an invariant() in the future. + // It has only been added in Fiber to match the (unintentional) behavior in Stack. + if (typeof instance.getChildContext !== "function") { + { + var componentName = getComponentName(type) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warningWithoutStack$1( + false, + "%s.childContextTypes is specified but there is no getChildContext() method " + + "on the instance. You can either define getChildContext() on %s or remove " + + "childContextTypes from it.", + componentName, + componentName + ); + } + } + return parentContext; + } + + var childContext = void 0; + { + setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + setCurrentPhase(null); + } + for (var contextKey in childContext) { + (function() { + if (!(contextKey in childContextTypes)) { + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + } + })(); + } + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + childContextTypes, + childContext, + "child context", + name, + // In practice, there is one case in which we won't get a stack. It's when + // somebody calls unstable_renderSubtreeIntoContainer() and we process + // context from the parent component instance. The stack will be missing + // because it's outside of the reconciliation, and so the pointer has not + // been set. This is rare and doesn't matter. We'll also remove that API. + getCurrentFiberStackInDev + ); + } + + return Object.assign({}, parentContext, childContext); +} + +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + // We push the context as early as possible to ensure stack integrity. + // If the instance does not exist yet, we will push null at first, + // and replace it on the stack later when invalidating the context. + var memoizedMergedChildContext = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + + // Remember the parent context so we can merge with it later. + // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. + previousContext = contextStackCursor.current; + push(contextStackCursor, memoizedMergedChildContext, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + + return true; +} + +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + (function() { + if (!instance) { + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + if (didChange) { + // Merge parent and own context. + // Skip this if we're not updating due to sCU. + // This avoids unnecessarily recomputing memoized values. + var mergedContext = processChildContext( + workInProgress, + type, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + + // Replace the old (or empty) context with the new one. + // It is important to unwind the context in the reverse order. + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + // Now push the new context and mark that it has changed. + push(contextStackCursor, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } +} + +function findCurrentUnmaskedContext(fiber) { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + (function() { + if (!(isFiberMounted(fiber) && fiber.tag === ClassComponent)) { + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + var node = fiber; + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; + case ClassComponent: { + var Component = node.type; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + break; + } + } + node = node.return; + } while (node !== null); + (function() { + { + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +var hasLoggedError = false; + +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) { + if (true && !hasLoggedError) { + hasLoggedError = true; + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s", + err + ); + } + } + }; +} + +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; + +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; + } + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; + } + if (!hook.supportsFiber) { + { + warningWithoutStack$1( + false, + "The installed version of React DevTools is too old and will not work " + + "with the current version of React. Please update React DevTools. " + + "https://fb.me/react-devtools" + ); + } + // DevTools exists, even though it doesn't support Fiber. + return true; + } + try { + var rendererID = hook.inject(internals); + // We have successfully injected, so now it is safe to set up hooks. + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + { + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s.", + err + ); + } + } + // DevTools exists + return true; +} + +function onCommitRoot(root) { + if (typeof onCommitFiberRoot === "function") { + onCommitFiberRoot(root); + } +} + +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === "function") { + onCommitFiberUnmount(fiber); + } +} + +// Max 31 bit integer. The max integer size in V8 for 32-bit systems. +// Math.pow(2, 30) - 1 +// 0b111111111111111111111111111111 +var MAX_SIGNED_31_BIT_INT = 1073741823; + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority; +var Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback; +var Scheduler_cancelCallback = Scheduler.unstable_cancelCallback; +var Scheduler_shouldYield = Scheduler.unstable_shouldYield; +var Scheduler_now = Scheduler.unstable_now; +var Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel; +var Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority; +var Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; +var Scheduler_NormalPriority = Scheduler.unstable_NormalPriority; +var Scheduler_LowPriority = Scheduler.unstable_LowPriority; +var Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; + +if (enableSchedulerTracing) { + // Provide explicit error message when production+profiling bundle of e.g. + // react-dom is used with production (non-profiling) bundle of + // scheduler/tracing + (function() { + if ( + !( + tracing.__interactionsRef != null && + tracing.__interactionsRef.current != null + ) + ) { + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); + } + })(); +} + +var fakeCallbackNode = {}; + +// Except for NoPriority, these correspond to Scheduler priorities. We use +// ascending numbers so we can compare them like numbers. They start at 90 to +// avoid clashing with Scheduler's priorities. +var ImmediatePriority = 99; +var UserBlockingPriority = 98; +var NormalPriority = 97; +var LowPriority = 96; +var IdlePriority = 95; +// NoPriority is the absence of priority. Also React-only. + +var shouldYield = disableYielding + ? function() { + return false; + } // Never yield when `disableYielding` is on + : Scheduler_shouldYield; + +var immediateQueue = null; +var immediateQueueCallbackNode = null; +var isFlushingImmediate = false; +var initialTimeMs = Scheduler_now(); + +// If the initial timestamp is reasonably small, use Scheduler's `now` directly. +// This will be the case for modern browsers that support `performance.now`. In +// older browsers, Scheduler falls back to `Date.now`, which returns a Unix +// timestamp. In that case, subtract the module initialization time to simulate +// the behavior of performance.now and keep our times small enough to fit +// within 32 bits. +// TODO: Consider lifting this into Scheduler. +var now = + initialTimeMs < 10000 + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; + +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return ImmediatePriority; + case Scheduler_UserBlockingPriority: + return UserBlockingPriority; + case Scheduler_NormalPriority: + return NormalPriority; + case Scheduler_LowPriority: + return LowPriority; + case Scheduler_IdlePriority: + return IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case ImmediatePriority: + return Scheduler_ImmediatePriority; + case UserBlockingPriority: + return Scheduler_UserBlockingPriority; + case NormalPriority: + return Scheduler_NormalPriority; + case LowPriority: + return Scheduler_LowPriority; + case IdlePriority: + return Scheduler_IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function runWithPriority(reactPriorityLevel, fn) { + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(priorityLevel, fn); +} + +function scheduleCallback(reactPriorityLevel, callback, options) { + if (reactPriorityLevel === ImmediatePriority) { + // Push this callback into an internal queue. We'll flush these either in + // the next tick, or earlier if something calls `flushImmediateQueue`. + if (immediateQueue === null) { + immediateQueue = [callback]; + // Flush the queue in the next tick, at the earliest. + immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ); + } else { + // Push onto existing queue. Don't need to schedule a callback because + // we already scheduled one when we created the queue. + immediateQueue.push(callback); + } + return fakeCallbackNode; + } + // Otherwise pass through to Scheduler. + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(priorityLevel, callback, options); +} + +function cancelCallback(callbackNode) { + if (callbackNode !== fakeCallbackNode) { + Scheduler_cancelCallback(callbackNode); + } +} + +function flushImmediateQueue() { + if (immediateQueueCallbackNode !== null) { + Scheduler_cancelCallback(immediateQueueCallbackNode); + } + flushImmediateQueueImpl(); +} + +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && immediateQueue !== null) { + // Prevent re-entrancy. + isFlushingImmediate = true; + var i = 0; + try { + var _isSync = true; + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do { + callback = callback(_isSync); + } while (callback !== null); + } + immediateQueue = null; + } catch (error) { + // If something throws, leave the remaining callbacks on the queue. + if (immediateQueue !== null) { + immediateQueue = immediateQueue.slice(i + 1); + } + // Resume flushing in the next tick + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ); + throw error; + } finally { + isFlushingImmediate = false; + } + } +} + +var NoWork = 0; +var Never = 1; +var Sync = MAX_SIGNED_31_BIT_INT; + +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = MAX_SIGNED_31_BIT_INT - 1; + +// 1 unit of expiration time represents 10ms. +function msToExpirationTime(ms) { + // Always add an offset so that we don't clash with the magic number for NoWork. + return MAGIC_NUMBER_OFFSET - ((ms / UNIT_SIZE) | 0); +} + +function expirationTimeToMs(expirationTime) { + return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; +} + +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ( + MAGIC_NUMBER_OFFSET - + ceiling( + MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ) + ); +} + +// TODO: This corresponds to Scheduler's NormalPriority, not LowPriority. Update +// the names to reflect. +var LOW_PRIORITY_EXPIRATION = 5000; +var LOW_PRIORITY_BATCH_SIZE = 250; + +function computeAsyncExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + LOW_PRIORITY_EXPIRATION, + LOW_PRIORITY_BATCH_SIZE + ); +} + +// Same as computeAsyncExpiration but without the bucketing logic. This is +// used to compute timestamps instead of actual expiration times. +function computeAsyncExpirationNoBucket(currentTime) { + return currentTime - LOW_PRIORITY_EXPIRATION / UNIT_SIZE; +} + +// We intentionally set a higher expiration time for interactive updates in +// dev than in production. +// +// If the main thread is being blocked so long that you hit the expiration, +// it's a problem that could be solved with better scheduling. +// +// People will be more likely to notice this and fix it with the long +// expiration time in development. +// +// In production we opt for better UX at the risk of masking scheduling +// problems, by expiring fast. +var HIGH_PRIORITY_EXPIRATION = 500; +var HIGH_PRIORITY_BATCH_SIZE = 100; + +function computeInteractiveExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + HIGH_PRIORITY_EXPIRATION, + HIGH_PRIORITY_BATCH_SIZE + ); +} + +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (expirationTime === Sync) { + return ImmediatePriority; + } + if (expirationTime === Never) { + return IdlePriority; + } + var msUntil = + expirationTimeToMs(expirationTime) - expirationTimeToMs(currentTime); + if (msUntil <= 0) { + return ImmediatePriority; + } + if (msUntil <= HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE) { + return UserBlockingPriority; + } + if (msUntil <= LOW_PRIORITY_EXPIRATION + LOW_PRIORITY_BATCH_SIZE) { + return NormalPriority; + } + + // TODO: Handle LowPriority + + // Assume anything lower has idle priority + return IdlePriority; +} + +var NoContext = 0; +var ConcurrentMode = 1; +var StrictMode = 2; +var ProfileMode = 4; + +var hasBadMapPolyfill = void 0; + +{ + hasBadMapPolyfill = false; + try { + var nonExtensibleObject = Object.preventExtensions({}); + var testMap = new Map([[nonExtensibleObject, null]]); + var testSet = new Set([nonExtensibleObject]); + // This is necessary for Rollup to not consider these unused. + // https://github.com/rollup/rollup/issues/1771 + // TODO: we can remove these if Rollup fixes the bug. + testMap.set(0, 0); + testSet.add(0); + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } +} + +// A Fiber is work on a Component that needs to be done or was done. There can +// be more than one per component. + +var debugCounter = void 0; + +{ + debugCounter = 1; +} + +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; + + // Fiber + this.return = null; + this.child = null; + this.sibling = null; + this.index = 0; + + this.ref = null; + + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; + this.contextDependencies = null; + + this.mode = mode; + + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; + + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + this.childExpirationTime = NoWork; + + this.alternate = null; + + if (enableProfilerTimer) { + // Note: The following is done to avoid a v8 performance cliff. + // + // Initializing the fields below to smis and later updating them with + // double values will cause Fibers to end up having separate shapes. + // This behavior/bug has something to do with Object.preventExtension(). + // Fortunately this only impacts DEV builds. + // Unfortunately it makes React unusably slow for some applications. + // To work around this, initialize the fields below with doubles. + // + // Learn more about this here: + // https://github.com/facebook/react/issues/14365 + // https://bugs.chromium.org/p/v8/issues/detail?id=8538 + this.actualDuration = Number.NaN; + this.actualStartTime = Number.NaN; + this.selfBaseDuration = Number.NaN; + this.treeBaseDuration = Number.NaN; + + // It's okay to replace the initial doubles with smis after initialization. + // This won't trigger the performance cliff mentioned above, + // and it simplifies other profiler code (including DevTools). + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + this._debugHookTypes = null; + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); + } + } +} + +// This is a constructor function, rather than a POJO constructor, still +// please ensure we do the following: +// 1) Nobody should add any instance methods on this. Instance methods can be +// more difficult to predict when they get optimized and they are almost +// never inlined properly in static compilers. +// 2) Nobody should rely on `instanceof Fiber` for type testing. We should +// always know when it is a fiber. +// 3) We might want to experiment with using numeric keys since they are easier +// to optimize in a non-JIT environment. +// 4) We can easily go from a constructor to a createFiber object literal if that +// is faster. +// 5) It should be easy to port this to a C struct and keep a C implementation +// compatible. +var createFiber = function(tag, pendingProps, key, mode) { + // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +}; + +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} + +function isSimpleFunctionComponent(type) { + return ( + typeof type === "function" && + !shouldConstruct(type) && + type.defaultProps === undefined + ); +} + +function resolveLazyComponentTag(Component) { + if (typeof Component === "function") { + return shouldConstruct(Component) ? ClassComponent : FunctionComponent; + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + return ForwardRef; + } + if ($$typeof === REACT_MEMO_TYPE) { + return MemoComponent; + } + } + return IndeterminateComponent; +} + +// This is used to create an alternate fiber to do work on. +function createWorkInProgress(current, pendingProps, expirationTime) { + var workInProgress = current.alternate; + if (workInProgress === null) { + // We use a double buffering pooling technique because we know that we'll + // only ever need at most two versions of a tree. We pool the "other" unused + // node that we're free to reuse. This is lazily created to avoid allocating + // extra objects for things that are never updated. It also allow us to + // reclaim the extra memory if needed. + workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + ); + workInProgress.elementType = current.elementType; + workInProgress.type = current.type; + workInProgress.stateNode = current.stateNode; + + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } + + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; + + // We already have an alternate. + // Reset the effect tag. + workInProgress.effectTag = NoEffect; + + // The effect list is no longer valid. + workInProgress.nextEffect = null; + workInProgress.firstEffect = null; + workInProgress.lastEffect = null; + + if (enableProfilerTimer) { + // We intentionally reset, rather than copy, actualDuration & actualStartTime. + // This prevents time from endlessly accumulating in new commits. + // This has the downside of resetting values for different priority renders, + // But works for yielding (the common case) and should support resuming. + workInProgress.actualDuration = 0; + workInProgress.actualStartTime = -1; + } + } + + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + if (enableProfilerTimer) { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + return workInProgress; +} + +function createHostRootFiber(isConcurrent) { + var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; + + if (enableProfilerTimer && isDevToolsPresent) { + // Always collect profile timings when DevTools are present. + // This enables DevTools to start capturing timing at any point– + // Without some nodes in the tree having empty base times. + mode |= ProfileMode; + } + + return createFiber(HostRoot, null, null, mode); +} + +function createFiberFromTypeAndProps( + type, // React$ElementType + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiber = void 0; + + var fiberTag = IndeterminateComponent; + // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + var resolvedType = type; + if (typeof type === "function") { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; + } + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | ConcurrentMode | StrictMode, + expirationTime, + key + ); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | StrictMode, + expirationTime, + key + ); + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, expirationTime, key); + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, expirationTime, key); + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break getTag; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break getTag; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break getTag; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; + case REACT_EVENT_COMPONENT_TYPE: + if (enableEventAPI) { + return createFiberFromEventComponent( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + case REACT_EVENT_TARGET_TYPE: + if (enableEventAPI) { + return createFiberFromEventTarget( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + } + } + var info = ""; + { + if ( + type === undefined || + (typeof type === "object" && + type !== null && + Object.keys(type).length === 0) + ) { + info += + " You likely forgot to export your component from the file " + + "it's defined in, or you might have mixed up default and " + + "named imports."; + } + var ownerName = owner ? getComponentName(owner.type) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } + (function() { + { + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (type == null ? type : typeof type) + + "." + + info + ); + } + })(); + } + } + } + + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; + } + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime + ); + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; + } + return fiber; +} + +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventComponent( + eventComponent, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventComponent, pendingProps, key, mode); + fiber.elementType = eventComponent; + fiber.type = eventComponent; + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventTarget( + eventTarget, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventTarget, pendingProps, key, mode); + fiber.elementType = eventTarget; + fiber.type = eventTarget; + fiber.expirationTime = expirationTime; + // Store latest props + fiber.stateNode = { + props: pendingProps + }; + return fiber; +} + +function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { + { + if ( + typeof pendingProps.id !== "string" || + typeof pendingProps.onRender !== "function" + ) { + warningWithoutStack$1( + false, + 'Profiler must specify an "id" string and "onRender" function as props' + ); + } + } + + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + // TODO: The Profiler fiber shouldn't have a type. It has a tag. + fiber.elementType = REACT_PROFILER_TYPE; + fiber.type = REACT_PROFILER_TYPE; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(Mode, pendingProps, key, mode); + + // TODO: The Mode fiber shouldn't have a type. It has a tag. + var type = + (mode & ConcurrentMode) === NoContext + ? REACT_STRICT_MODE_TYPE + : REACT_CONCURRENT_MODE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + + // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. + var type = REACT_SUSPENSE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoContext); + // TODO: These should not need a type. + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + return fiber; +} + +function createFiberFromPortal(portal, mode, expirationTime) { + var pendingProps = portal.children !== null ? portal.children : []; + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); + fiber.expirationTime = expirationTime; + fiber.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, // Used by persistent updates + implementation: portal.implementation + }; + return fiber; +} + +// Used for stashing WIP properties to replay failed work in DEV. +function assignFiberPropertiesInDEV(target, source) { + if (target === null) { + // This Fiber's initial properties will always be overwritten. + // We only use a Fiber to ensure the same hidden class so DEV isn't slow. + target = createFiber(IndeterminateComponent, null, null, NoContext); + } + + // This is intentionally written as a list of all properties. + // We tried to use Object.assign() instead but this is called in + // the hottest path, and Object.assign() was too slow: + // https://github.com/facebook/react/issues/12502 + // This code is DEV-only so size is not a concern. + + target.tag = source.tag; + target.key = source.key; + target.elementType = source.elementType; + target.type = source.type; + target.stateNode = source.stateNode; + target.return = source.return; + target.child = source.child; + target.sibling = source.sibling; + target.index = source.index; + target.ref = source.ref; + target.pendingProps = source.pendingProps; + target.memoizedProps = source.memoizedProps; + target.updateQueue = source.updateQueue; + target.memoizedState = source.memoizedState; + target.contextDependencies = source.contextDependencies; + target.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.childExpirationTime = source.childExpirationTime; + target.alternate = source.alternate; + if (enableProfilerTimer) { + target.actualDuration = source.actualDuration; + target.actualStartTime = source.actualStartTime; + target.selfBaseDuration = source.selfBaseDuration; + target.treeBaseDuration = source.treeBaseDuration; + } + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + target._debugHookTypes = source._debugHookTypes; + return target; +} + +// TODO: This should be lifted into the renderer. + +// The following attributes are only used by interaction tracing builds. +// They enable interactions to be associated with their async work, +// And expose interaction metadata to the React DevTools Profiler plugin. +// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. + +// Exported FiberRoot type includes all properties, +// To avoid requiring potentially error-prone :any casts throughout the project. +// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). +// The types are defined separately within this file to ensure they stay in sync. +// (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) + +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pendingChildren = null; + this.pingCache = null; + this.pendingCommitExpirationTime = NoWork; + this.finishedWork = null; + this.timeoutHandle = noTimeout; + this.context = null; + this.pendingContext = null; + this.hydrate = hydrate; + this.firstBatch = null; + this.callbackNode = null; + this.callbackExpirationTime = NoWork; + this.firstPendingTime = NoWork; + this.lastPendingTime = NoWork; + this.pingTime = NoWork; + + if (enableSchedulerTracing) { + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); + } +} + +function createFiberRoot(containerInfo, isConcurrent, hydrate) { + var root = new FiberRootNode(containerInfo, hydrate); + + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isConcurrent); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + + return root; +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warning = warningWithoutStack$1; + +{ + warning = function(condition, format) { + if (condition) { + return; + } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame.getStackAddendum(); + // eslint-disable-next-line react-internal/warning-and-invariant-args + + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + warningWithoutStack$1.apply( + undefined, + [false, format + "%s"].concat(args, [stack]) + ); + }; +} + +var warning$1 = warning; + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x, y) { + return ( + (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare + ); +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA, objB) { + if (is(objA, objB)) { + return true; + } + + if ( + typeof objA !== "object" || + objA === null || + typeof objB !== "object" || + objB === null + ) { + return false; + } + + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + for (var i = 0; i < keysA.length; i++) { + if ( + !hasOwnProperty.call(objB, keysA[i]) || + !is(objA[keysA[i]], objB[keysA[i]]) + ) { + return false; + } + } + + return true; +} + +/** + * Forked from fbjs/warning: + * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js + * + * Only change is we use console.warn instead of console.error, + * and do nothing when 'console' is not supported. + * This really simplifies the code. + * --- + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var lowPriorityWarning = function() {}; + +{ + var printWarning = function(format) { + for ( + var _len = arguments.length, + args = Array(_len > 1 ? _len - 1 : 0), + _key = 1; + _key < _len; + _key++ + ) { + args[_key - 1] = arguments[_key]; + } + + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + if (typeof console !== "undefined") { + console.warn(message); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} + }; + + lowPriorityWarning = function(condition, format) { + if (format === undefined) { + throw new Error( + "`lowPriorityWarning(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (!condition) { + for ( + var _len2 = arguments.length, + args = Array(_len2 > 2 ? _len2 - 2 : 0), + _key2 = 2; + _key2 < _len2; + _key2++ + ) { + args[_key2 - 2] = arguments[_key2]; + } + + printWarning.apply(undefined, [format].concat(args)); + } + }; +} + +var lowPriorityWarning$1 = lowPriorityWarning; + +var ReactStrictModeWarnings = { + discardPendingWarnings: function() {}, + flushPendingDeprecationWarnings: function() {}, + flushPendingUnsafeLifecycleWarnings: function() {}, + recordDeprecationWarnings: function(fiber, instance) {}, + recordUnsafeLifecycleWarnings: function(fiber, instance) {}, + recordLegacyContextWarning: function(fiber, instance) {}, + flushLegacyContextWarning: function() {} +}; + +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; + + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); + var pendingLegacyContextWarning = new Map(); + + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = new Set(); + var didWarnAboutLegacyContext = new Set(); + + var setToSortedString = function(set) { + var array = []; + set.forEach(function(value) { + array.push(value); + }); + return array.sort().join(", "); + }; + + ReactStrictModeWarnings.discardPendingWarnings = function() { + pendingComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUnsafeLifecycleWarnings = new Map(); + pendingLegacyContextWarning = new Map(); + }; + + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMessages = []; + + Object.keys(lifecycleWarningsMap).forEach(function(lifecycle) { + var lifecycleWarnings = lifecycleWarningsMap[lifecycle]; + if (lifecycleWarnings.length > 0) { + var componentNames = new Set(); + lifecycleWarnings.forEach(function(fiber) { + componentNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = setToSortedString(componentNames); + + lifecyclesWarningMessages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); + + if (lifecyclesWarningMessages.length > 0) { + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Unsafe lifecycle methods were found within a strict-mode tree:%s" + + "\n\n%s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + lifecyclesWarningMessages.join("\n\n") + ); + } + }); + + pendingUnsafeLifecycleWarnings = new Map(); + }; + + var findStrictRoot = function(fiber) { + var maybeStrictRoot = null; + + var node = fiber; + while (node !== null) { + if (node.mode & StrictMode) { + maybeStrictRoot = node; + } + node = node.return; + } + + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillMount is deprecated and will be removed in the next major version. " + + "Use componentDidMount instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillMount." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + sortedNames + ); + + pendingComponentWillMountWarnings = []; + } + + if (pendingComponentWillReceivePropsWarnings.length > 0) { + var _uniqueNames = new Set(); + pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { + _uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames = setToSortedString(_uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillReceiveProps is deprecated and will be removed in the next major version. " + + "Use static getDerivedStateFromProps instead." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames + ); + + pendingComponentWillReceivePropsWarnings = []; + } + + if (pendingComponentWillUpdateWarnings.length > 0) { + var _uniqueNames2 = new Set(); + pendingComponentWillUpdateWarnings.forEach(function(fiber) { + _uniqueNames2.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames2 = setToSortedString(_uniqueNames2); + + lowPriorityWarning$1( + false, + "componentWillUpdate is deprecated and will be removed in the next major version. " + + "Use componentDidUpdate instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillUpdate." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames2 + ); + + pendingComponentWillUpdateWarnings = []; + } + }; + + ReactStrictModeWarnings.recordDeprecationWarnings = function( + fiber, + instance + ) { + // Dedup strategy: Warn once per component. + if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { + return; + } + + // Don't warn about react-lifecycles-compat polyfilled components. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } + }; + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + // This is difficult to track any other way since component names + // are often vague and are likely to collide between 3rd party libraries. + // An expand property is probably okay to use here since it's DEV-only, + // and will only be set in the event of serious warnings. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } + + var warningsForRoot = void 0; + if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { + warningsForRoot = { + UNSAFE_componentWillMount: [], + UNSAFE_componentWillReceiveProps: [], + UNSAFE_componentWillUpdate: [] + }; + + pendingUnsafeLifecycleWarnings.set(strictRoot, warningsForRoot); + } else { + warningsForRoot = pendingUnsafeLifecycleWarnings.get(strictRoot); + } + + var unsafeLifecycles = []; + if ( + (typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + (typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true) || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + (typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + } + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); + } + }; + + ReactStrictModeWarnings.recordLegacyContextWarning = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } + + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } + warningsForRoot.push(fiber); + } + }; + + ReactStrictModeWarnings.flushLegacyContextWarning = function() { + pendingLegacyContextWarning.forEach(function(fiberArray, strictRoot) { + var uniqueNames = new Set(); + fiberArray.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Legacy context API has been detected within a strict-mode tree: %s" + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + sortedNames + ); + }); + }; +} + +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = Object.assign({}, baseProps); + var defaultProps = Component.defaultProps; + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; + } + } + return props; + } + return baseProps; +} + +function readLazyComponentType(lazyComponent) { + var status = lazyComponent._status; + var result = lazyComponent._result; + switch (status) { + case Resolved: { + var Component = result; + return Component; + } + case Rejected: { + var error = result; + throw error; + } + case Pending: { + var thenable = result; + throw thenable; + } + default: { + lazyComponent._status = Pending; + var ctor = lazyComponent._ctor; + var _thenable = ctor(); + _thenable.then( + function(moduleObject) { + if (lazyComponent._status === Pending) { + var defaultExport = moduleObject.default; + { + if (defaultExport === undefined) { + warning$1( + false, + "lazy: Expected the result of a dynamic import() call. " + + "Instead received: %s\n\nYour code should look like: \n " + + "const MyComponent = lazy(() => import('./MyComponent'))", + moduleObject + ); + } + } + lazyComponent._status = Resolved; + lazyComponent._result = defaultExport; + } + }, + function(error) { + if (lazyComponent._status === Pending) { + lazyComponent._status = Rejected; + lazyComponent._result = error; + } + } + ); + // Handle synchronous thenables. + switch (lazyComponent._status) { + case Resolved: + return lazyComponent._result; + case Rejected: + throw lazyComponent._result; + } + lazyComponent._result = _thenable; + throw _thenable; + } + } +} + +var valueCursor = createCursor(null); + +var rendererSigil = void 0; +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} + +var currentlyRenderingFiber = null; +var lastContextDependency = null; +var lastContextWithAllBitsObserved = null; + +var isDisallowedContextReadInDEV = false; + +function resetContextDependences() { + // This is called right before React yields execution, to ensure `readContext` + // cannot be called outside the render phase. + currentlyRenderingFiber = null; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + { + isDisallowedContextReadInDEV = false; + } +} + +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} + +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} + +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + + if (isPrimaryRenderer) { + push(valueCursor, context._currentValue, providerFiber); + + context._currentValue = nextValue; + { + !( + context._currentRenderer === undefined || + context._currentRenderer === null || + context._currentRenderer === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer = rendererSigil; + } + } else { + push(valueCursor, context._currentValue2, providerFiber); + + context._currentValue2 = nextValue; + { + !( + context._currentRenderer2 === undefined || + context._currentRenderer2 === null || + context._currentRenderer2 === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer2 = rendererSigil; + } + } +} + +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + + pop(valueCursor, providerFiber); + + var context = providerFiber.type._context; + if (isPrimaryRenderer) { + context._currentValue = currentValue; + } else { + context._currentValue2 = currentValue; + } +} + +function calculateChangedBits(context, newValue, oldValue) { + if (is(oldValue, newValue)) { + // No change + return 0; + } else { + var changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + + { + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning$1( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; + } + return changedBits | 0; + } +} + +function scheduleWorkOnParentPath(parent, renderExpirationTime) { + // Update the child expiration time of all the ancestors, including + // the alternates. + var node = parent; + while (node !== null) { + var alternate = node.alternate; + if (node.childExpirationTime < renderExpirationTime) { + node.childExpirationTime = renderExpirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; + } + node = node.return; + } +} + +function propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime +) { + var fiber = workInProgress.child; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } + while (fiber !== null) { + var nextFiber = void 0; + + // Visit this fiber. + var list = fiber.contextDependencies; + if (list !== null) { + nextFiber = fiber.child; + + var dependency = list.first; + while (dependency !== null) { + // Check if the context matches. + if ( + dependency.context === context && + (dependency.observedBits & changedBits) !== 0 + ) { + // Match! Schedule an update on this fiber. + + if (fiber.tag === ClassComponent) { + // Schedule a force update on the work-in-progress. + var update = createUpdate(renderExpirationTime); + update.tag = ForceUpdate; + // TODO: Because we don't have a work-in-progress, this will add the + // update to the current fiber, too, which means it will persist even if + // this render is thrown away. Since it's a race condition, not sure it's + // worth fixing. + enqueueUpdate(fiber, update); + } + + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var alternate = fiber.alternate; + if ( + alternate !== null && + alternate.expirationTime < renderExpirationTime + ) { + alternate.expirationTime = renderExpirationTime; + } + + scheduleWorkOnParentPath(fiber.return, renderExpirationTime); + + // Mark the expiration time on the list, too. + if (list.expirationTime < renderExpirationTime) { + list.expirationTime = renderExpirationTime; + } + + // Since we already found a match, we can stop traversing the + // dependency list. + break; + } + dependency = dependency.next; + } + } else if (fiber.tag === ContextProvider) { + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + } else if ( + enableSuspenseServerRenderer && + fiber.tag === DehydratedSuspenseComponent + ) { + // If a dehydrated suspense component is in this subtree, we don't know + // if it will have any context consumers in it. The best we can do is + // mark it as having updates on its children. + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var _alternate = fiber.alternate; + if ( + _alternate !== null && + _alternate.expirationTime < renderExpirationTime + ) { + _alternate.expirationTime = renderExpirationTime; + } + // This is intentionally passing this fiber as the parent + // because we want to schedule this fiber as having work + // on its children. We'll use the childExpirationTime on + // this fiber to indicate that a context has changed. + scheduleWorkOnParentPath(fiber, renderExpirationTime); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } + + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber.return = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } + var sibling = nextFiber.sibling; + if (sibling !== null) { + // Set the return pointer of the sibling to the work-in-progress fiber. + sibling.return = nextFiber.return; + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber.return; + } + } + fiber = nextFiber; + } +} + +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + + var currentDependencies = workInProgress.contextDependencies; + if ( + currentDependencies !== null && + currentDependencies.expirationTime >= renderExpirationTime + ) { + // Context list has a pending update. Mark that this fiber performed work. + markWorkInProgressReceivedUpdate(); + } + + // Reset the work-in-progress list + workInProgress.contextDependencies = null; +} + +function readContext(context, observedBits) { + { + // This warning would fire if you read context inside a Hook like useMemo. + // Unlike the class check below, it's not enforced in production for perf. + !!isDisallowedContextReadInDEV + ? warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ) + : void 0; + } + + if (lastContextWithAllBitsObserved === context) { + // Nothing to do. We already observe everything in this context. + } else if (observedBits === false || observedBits === 0) { + // Do not observe any updates. + } else { + var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. + if ( + typeof observedBits !== "number" || + observedBits === MAX_SIGNED_31_BIT_INT + ) { + // Observe all updates. + lastContextWithAllBitsObserved = context; + resolvedObservedBits = MAX_SIGNED_31_BIT_INT; + } else { + resolvedObservedBits = observedBits; + } + + var contextItem = { + context: context, + observedBits: resolvedObservedBits, + next: null + }; + + if (lastContextDependency === null) { + (function() { + if (!(currentlyRenderingFiber !== null)) { + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + } + })(); + + // This is the first dependency for this component. Create a new list. + lastContextDependency = contextItem; + currentlyRenderingFiber.contextDependencies = { + first: contextItem, + expirationTime: NoWork + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; + } + } + return isPrimaryRenderer ? context._currentValue : context._currentValue2; +} + +// UpdateQueue is a linked list of prioritized updates. +// +// Like fibers, update queues come in pairs: a current queue, which represents +// the visible state of the screen, and a work-in-progress queue, which can be +// mutated and processed asynchronously before it is committed — a form of +// double buffering. If a work-in-progress render is discarded before finishing, +// we create a new work-in-progress by cloning the current queue. +// +// Both queues share a persistent, singly-linked list structure. To schedule an +// update, we append it to the end of both queues. Each queue maintains a +// pointer to first update in the persistent list that hasn't been processed. +// The work-in-progress pointer always has a position equal to or greater than +// the current queue, since we always work on that one. The current queue's +// pointer is only updated during the commit phase, when we swap in the +// work-in-progress. +// +// For example: +// +// Current pointer: A - B - C - D - E - F +// Work-in-progress pointer: D - E - F +// ^ +// The work-in-progress queue has +// processed more updates than current. +// +// The reason we append to both queues is because otherwise we might drop +// updates without ever processing them. For example, if we only add updates to +// the work-in-progress queue, some updates could be lost whenever a work-in +// -progress render restarts by cloning from current. Similarly, if we only add +// updates to the current queue, the updates will be lost whenever an already +// in-progress queue commits and swaps with the current queue. However, by +// adding to both queues, we guarantee that the update will be part of the next +// work-in-progress. (And because the work-in-progress queue becomes the +// current queue once it commits, there's no danger of applying the same +// update twice.) +// +// Prioritization +// -------------- +// +// Updates are not sorted by priority, but by insertion; new updates are always +// appended to the end of the list. +// +// The priority is still important, though. When processing the update queue +// during the render phase, only the updates with sufficient priority are +// included in the result. If we skip an update because it has insufficient +// priority, it remains in the queue to be processed later, during a lower +// priority render. Crucially, all updates subsequent to a skipped update also +// remain in the queue *regardless of their priority*. That means high priority +// updates are sometimes processed twice, at two separate priorities. We also +// keep track of a base state, that represents the state before the first +// update in the queue is applied. +// +// For example: +// +// Given a base state of '', and the following queue of updates +// +// A1 - B2 - C1 - D2 +// +// where the number indicates the priority, and the update is applied to the +// previous state by appending a letter, React will process these updates as +// two separate renders, one per distinct priority level: +// +// First render, at priority 1: +// Base state: '' +// Updates: [A1, C1] +// Result state: 'AC' +// +// Second render, at priority 2: +// Base state: 'A' <- The base state does not include C1, +// because B2 was skipped. +// Updates: [B2, C1, D2] <- C1 was rebased on top of B2 +// Result state: 'ABCD' +// +// Because we process updates in insertion order, and rebase high priority +// updates when preceding updates are skipped, the final result is deterministic +// regardless of priority. Intermediate state may vary according to system +// resources, but the final state is always the same. + +var UpdateState = 0; +var ReplaceState = 1; +var ForceUpdate = 2; +var CaptureUpdate = 3; + +// Global state that is reset at the beginning of calling `processUpdateQueue`. +// It should only be read right after calling `processUpdateQueue`, via +// `checkHasForceUpdateAfterProcessing`. +var hasForceUpdate = false; + +var didWarnUpdateInsideUpdate = void 0; +var currentlyProcessingQueue = void 0; + +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} + +function createUpdateQueue(baseState) { + var queue = { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function cloneUpdateQueue(currentQueue) { + var queue = { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + + // TODO: With resuming, if we bail out and resuse the child tree, we should + // keep these effects. + firstCapturedUpdate: null, + lastCapturedUpdate: null, + + firstEffect: null, + lastEffect: null, + + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + + tag: UpdateState, + payload: null, + callback: null, + + next: null, + nextEffect: null + }; +} + +function appendUpdateToQueue(queue, update) { + // Append the update to the end of the list. + if (queue.lastUpdate === null) { + // Queue is empty + queue.firstUpdate = queue.lastUpdate = update; + } else { + queue.lastUpdate.next = update; + queue.lastUpdate = update; + } +} + +function enqueueUpdate(fiber, update) { + // Update queues are created lazily. + var alternate = fiber.alternate; + var queue1 = void 0; + var queue2 = void 0; + if (alternate === null) { + // There's only one fiber. + queue1 = fiber.updateQueue; + queue2 = null; + if (queue1 === null) { + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + } + } else { + // There are two owners. + queue1 = fiber.updateQueue; + queue2 = alternate.updateQueue; + if (queue1 === null) { + if (queue2 === null) { + // Neither fiber has an update queue. Create new ones. + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ); + } else { + // Only one fiber has an update queue. Clone to create a new one. + queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); + } + } else { + if (queue2 === null) { + // Only one fiber has an update queue. Clone to create a new one. + queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); + } else { + // Both owners have an update queue. + } + } + } + if (queue2 === null || queue1 === queue2) { + // There's only a single queue. + appendUpdateToQueue(queue1, update); + } else { + // There are two queues. We need to append the update to both queues, + // while accounting for the persistent structure of the list — we don't + // want the same update to be added multiple times. + if (queue1.lastUpdate === null || queue2.lastUpdate === null) { + // One of the queues is not empty. We must add the update to both queues. + appendUpdateToQueue(queue1, update); + appendUpdateToQueue(queue2, update); + } else { + // Both queues are non-empty. The last update is the same in both lists, + // because of structural sharing. So, only append to one of the lists. + appendUpdateToQueue(queue1, update); + // But we still need to update the `lastUpdate` pointer of queue2. + queue2.lastUpdate = update; + } + } + + { + if ( + fiber.tag === ClassComponent && + (currentlyProcessingQueue === queue1 || + (queue2 !== null && currentlyProcessingQueue === queue2)) && + !didWarnUpdateInsideUpdate + ) { + warningWithoutStack$1( + false, + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback." + ); + didWarnUpdateInsideUpdate = true; + } + } +} + +function enqueueCapturedUpdate(workInProgress, update) { + // Captured updates go into a separate list, and only on the work-in- + // progress queue. + var workInProgressQueue = workInProgress.updateQueue; + if (workInProgressQueue === null) { + workInProgressQueue = workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + ); + } else { + // TODO: I put this here rather than createWorkInProgress so that we don't + // clone the queue unnecessarily. There's probably a better way to + // structure this. + workInProgressQueue = ensureWorkInProgressQueueIsAClone( + workInProgress, + workInProgressQueue + ); + } + + // Append the update to the end of the list. + if (workInProgressQueue.lastCapturedUpdate === null) { + // This is the first render phase update + workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; + } else { + workInProgressQueue.lastCapturedUpdate.next = update; + workInProgressQueue.lastCapturedUpdate = update; + } +} + +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + if (current !== null) { + // If the work-in-progress queue is equal to the current queue, + // we need to clone it first. + if (queue === current.updateQueue) { + queue = workInProgress.updateQueue = cloneUpdateQueue(queue); + } + } + return queue; +} + +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var _payload = update.payload; + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload.call(instance, prevState, nextProps); + } + } + var nextState = _payload.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + return nextState; + } + // State object + return _payload; + } + case CaptureUpdate: { + workInProgress.effectTag = + (workInProgress.effectTag & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough + case UpdateState: { + var _payload2 = update.payload; + var partialState = void 0; + if (typeof _payload2 === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload2.call(instance, prevState, nextProps); + } + } + partialState = _payload2.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload2; + } + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } + // Merge the partial state and the previous state. + return Object.assign({}, prevState, partialState); + } + case ForceUpdate: { + hasForceUpdate = true; + return prevState; + } + } + return prevState; +} + +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = false; + + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + + { + currentlyProcessingQueue = queue; + } + + // These values may change as we process the queue. + var newBaseState = queue.baseState; + var newFirstUpdate = null; + var newExpirationTime = NoWork; + + // Iterate through the list of updates to compute the result. + var update = queue.firstUpdate; + var resultState = newBaseState; + while (update !== null) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstUpdate === null) { + // This is the first skipped update. It will be the first update in + // the new list. + newFirstUpdate = update; + // Since this is the first update that was skipped, the current result + // is the new base state. + newBaseState = resultState; + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < updateExpirationTime) { + newExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process it and compute a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback = update.callback; + if (_callback !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastEffect === null) { + queue.firstEffect = queue.lastEffect = update; + } else { + queue.lastEffect.nextEffect = update; + queue.lastEffect = update; + } + } + } + // Continue to the next update. + update = update.next; + } + + // Separately, iterate though the list of captured updates. + var newFirstCapturedUpdate = null; + update = queue.firstCapturedUpdate; + while (update !== null) { + var _updateExpirationTime = update.expirationTime; + if (_updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstCapturedUpdate === null) { + // This is the first skipped captured update. It will be the first + // update in the new list. + newFirstCapturedUpdate = update; + // If this is the first update that was skipped, the current result is + // the new base state. + if (newFirstUpdate === null) { + newBaseState = resultState; + } + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < _updateExpirationTime) { + newExpirationTime = _updateExpirationTime; + } + } else { + // This update does have sufficient priority. Process it and compute + // a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback2 = update.callback; + if (_callback2 !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastCapturedEffect === null) { + queue.firstCapturedEffect = queue.lastCapturedEffect = update; + } else { + queue.lastCapturedEffect.nextEffect = update; + queue.lastCapturedEffect = update; + } + } + } + update = update.next; + } + + if (newFirstUpdate === null) { + queue.lastUpdate = null; + } + if (newFirstCapturedUpdate === null) { + queue.lastCapturedUpdate = null; + } else { + workInProgress.effectTag |= Callback; + } + if (newFirstUpdate === null && newFirstCapturedUpdate === null) { + // We processed every update, without skipping. That means the new base + // state is the same as the result state. + newBaseState = resultState; + } + + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = newFirstCapturedUpdate; + + // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; + + { + currentlyProcessingQueue = null; + } +} + +function callCallback(callback, context) { + (function() { + if (!(typeof callback === "function")) { + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + callback + ); + } + })(); + callback.call(context); +} + +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} + +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} + +function commitUpdateQueue( + finishedWork, + finishedQueue, + instance, + renderExpirationTime +) { + // If the finished render included captured updates, and there are still + // lower priority updates left over, we need to keep the captured updates + // in the queue so that they are rebased and not dropped once we process the + // queue again at the lower priority. + if (finishedQueue.firstCapturedUpdate !== null) { + // Join the captured update list to the end of the normal list. + if (finishedQueue.lastUpdate !== null) { + finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; + finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; + } + // Clear the list of captured updates. + finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; + } + + // Commit the effects + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} + +function commitUpdateEffects(effect, instance) { + while (effect !== null) { + var _callback3 = effect.callback; + if (_callback3 !== null) { + effect.callback = null; + callCallback(_callback3, instance); + } + effect = effect.nextEffect; + } +} + +var fakeInternalInstance = {}; +var isArray$1 = Array.isArray; + +// React.Component uses a shared frozen object by default. +// We'll use it to determine whether we need to initialize legacy refs. +var emptyRefsObject = new React.Component().refs; + +var didWarnAboutStateAssignmentForComponent = void 0; +var didWarnAboutUninitializedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; +var didWarnAboutUndefinedDerivedState = void 0; +var warnOnUndefinedDerivedState = void 0; +var warnOnInvalidCallback = void 0; +var didWarnAboutDirectlyAssigningPropsToState = void 0; +var didWarnAboutContextTypeAndContextTypes = void 0; +var didWarnAboutInvalidateContextType = void 0; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutDirectlyAssigningPropsToState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutContextTypeAndContextTypes = new Set(); + didWarnAboutInvalidateContextType = new Set(); + + var didWarnOnInvalidCallback = new Set(); + + warnOnInvalidCallback = function(callback, callerName) { + if (callback === null || typeof callback === "function") { + return; + } + var key = callerName + "_" + callback; + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); + warningWithoutStack$1( + false, + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); + } + }; + + warnOnUndefinedDerivedState = function(type, partialState) { + if (partialState === undefined) { + var componentName = getComponentName(type) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warningWithoutStack$1( + false, + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName + ); + } + } + }; + + // This is so gross but it's at least non-critical and can be removed if + // it causes problems. This is meant to give a nicer error message for + // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, + // ...)) which otherwise throws a "_processChildContext is not a function" + // exception. + Object.defineProperty(fakeInternalInstance, "_processChildContext", { + enumerable: false, + value: function() { + (function() { + { + throw ReactError( + "_processChildContext is not available in React 16+. This likely means you have multiple copies of React and are attempting to nest a React 15 tree inside a React 16 tree using unstable_renderSubtreeIntoContainer, which isn't supported. Try to make sure you have only one copy of React (and ideally, switch to ReactDOM.createPortal)." + ); + } + })(); + } + }); + Object.freeze(fakeInternalInstance); +} + +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Invoke the function an extra time to help detect side-effects. + getDerivedStateFromProps(nextProps, prevState); + } + } + + var partialState = getDerivedStateFromProps(nextProps, prevState); + + { + warnOnUndefinedDerivedState(ctor, partialState); + } + // Merge the partial state and the previous state. + var memoizedState = + partialState === null || partialState === undefined + ? prevState + : Object.assign({}, prevState, partialState); + workInProgress.memoizedState = memoizedState; + + // Once the update queue is empty, persist the derived state onto the + // base state. + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && workInProgress.expirationTime === NoWork) { + updateQueue.baseState = memoizedState; + } +} + +var classComponentUpdater = { + isMounted: isMounted, + enqueueSetState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.payload = payload; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "setState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ReplaceState; + update.payload = payload; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "replaceState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueForceUpdate: function(inst, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ForceUpdate; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + } +}; + +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + var instance = workInProgress.stateNode; + if (typeof instance.shouldComponentUpdate === "function") { + startPhaseTimer(workInProgress, "shouldComponentUpdate"); + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + stopPhaseTimer(); + + { + !(shouldUpdate !== undefined) + ? warningWithoutStack$1( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(ctor) || "Component" + ) + : void 0; + } + + return shouldUpdate; + } + + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); + } + + return true; +} + +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; + { + var name = getComponentName(ctor) || "Component"; + var renderPresent = instance.render; + + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === "function") { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: you may have forgotten to define `render`.", + name + ); + } + } + + var noGetInitialStateOnES6 = + !instance.getInitialState || + instance.getInitialState.isReactClassApproved || + instance.state; + !noGetInitialStateOnES6 + ? warningWithoutStack$1( + false, + "getInitialState was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Did you mean to define a state property instead?", + name + ) + : void 0; + var noGetDefaultPropsOnES6 = + !instance.getDefaultProps || + instance.getDefaultProps.isReactClassApproved; + !noGetDefaultPropsOnES6 + ? warningWithoutStack$1( + false, + "getDefaultProps was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Use a static property to define defaultProps instead.", + name + ) + : void 0; + var noInstancePropTypes = !instance.propTypes; + !noInstancePropTypes + ? warningWithoutStack$1( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; + var noInstanceContextType = !instance.contextType; + !noInstanceContextType + ? warningWithoutStack$1( + false, + "contextType was defined as an instance property on %s. Use a static " + + "property to define contextType instead.", + name + ) + : void 0; + var noInstanceContextTypes = !instance.contextTypes; + !noInstanceContextTypes + ? warningWithoutStack$1( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; + + if ( + ctor.contextType && + ctor.contextTypes && + !didWarnAboutContextTypeAndContextTypes.has(ctor) + ) { + didWarnAboutContextTypeAndContextTypes.add(ctor); + warningWithoutStack$1( + false, + "%s declares both contextTypes and contextType static properties. " + + "The legacy contextTypes property will be ignored.", + name + ); + } + + var noComponentShouldUpdate = + typeof instance.componentShouldUpdate !== "function"; + !noComponentShouldUpdate + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + + "The name is phrased as a question because the function is " + + "expected to return a value.", + name + ) + : void 0; + if ( + ctor.prototype && + ctor.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" + ) { + warningWithoutStack$1( + false, + "%s has a method called shouldComponentUpdate(). " + + "shouldComponentUpdate should not be used when extending React.PureComponent. " + + "Please extend React.Component if shouldComponentUpdate is used.", + getComponentName(ctor) || "A pure component" + ); + } + var noComponentDidUnmount = + typeof instance.componentDidUnmount !== "function"; + !noComponentDidUnmount + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidUnmount(). But there is no such lifecycle method. " + + "Did you mean componentWillUnmount()?", + name + ) + : void 0; + var noComponentDidReceiveProps = + typeof instance.componentDidReceiveProps !== "function"; + !noComponentDidReceiveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidReceiveProps(). But there is no such lifecycle method. " + + "If you meant to update the state in response to changing props, " + + "use componentWillReceiveProps(). If you meant to fetch data or " + + "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", + name + ) + : void 0; + var noComponentWillRecieveProps = + typeof instance.componentWillRecieveProps !== "function"; + !noComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; + var noUnsafeComponentWillRecieveProps = + typeof instance.UNSAFE_componentWillRecieveProps !== "function"; + !noUnsafeComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; + var hasMutatedProps = instance.props !== newProps; + !(instance.props === undefined || !hasMutatedProps) + ? warningWithoutStack$1( + false, + "%s(...): When calling super() in `%s`, make sure to pass " + + "up the same props that your component's constructor was passed.", + name, + name + ) + : void 0; + var noInstanceDefaultProps = !instance.defaultProps; + !noInstanceDefaultProps + ? warningWithoutStack$1( + false, + "Setting defaultProps as an instance property on %s is not supported and will be ignored." + + " Instead, define defaultProps as a static property on %s.", + name, + name + ) + : void 0; + + if ( + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(ctor) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromProps() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noInstanceGetDerivedStateFromCatch = + typeof instance.getDerivedStateFromError !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromError() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof ctor.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() is defined as a static method " + + "and will be ignored. Instead, declare it as an instance method.", + name + ) + : void 0; + var _state = instance.state; + if (_state && (typeof _state !== "object" || isArray$1(_state))) { + warningWithoutStack$1( + false, + "%s.state: must be set to an object or null", + name + ); + } + if (typeof instance.getChildContext === "function") { + !(typeof ctor.childContextTypes === "object") + ? warningWithoutStack$1( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } + } +} + +function adoptClassInstance(workInProgress, instance) { + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; + // The instance needs access to the fiber so that it can schedule updates + set(instance, workInProgress); + { + instance._reactInternalInstance = fakeInternalInstance; + } +} + +function constructClassInstance( + workInProgress, + ctor, + props, + renderExpirationTime +) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = null; + var contextType = ctor.contextType; + + { + if ("contextType" in ctor) { + var isValid = + // Allow null for conditional declaration + contextType === null || + (contextType !== undefined && + contextType.$$typeof === REACT_CONTEXT_TYPE && + contextType._context === undefined); // Not a + + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + + var addendum = ""; + if (contextType === undefined) { + addendum = + " However, it is set to undefined. " + + "This can be caused by a typo or by mixing up named and default imports. " + + "This can also happen due to a circular dependency, so " + + "try moving the createContext() call to a separate file."; + } else if (typeof contextType !== "object") { + addendum = " However, it is set to a " + typeof contextType + "."; + } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { + addendum = " Did you accidentally pass the Context.Provider instead?"; + } else if (contextType._context !== undefined) { + // + addendum = " Did you accidentally pass the Context.Consumer instead?"; + } else { + addendum = + " However, it is set to an object with keys {" + + Object.keys(contextType).join(", ") + + "}."; + } + warningWithoutStack$1( + false, + "%s defines an invalid contextType. " + + "contextType should point to the Context object returned by React.createContext().%s", + getComponentName(ctor) || "Component", + addendum + ); + } + } + } + + if (typeof contextType === "object" && contextType !== null) { + context = readContext(contextType); + } else { + unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + var contextTypes = ctor.contextTypes; + isLegacyContextConsumer = + contextTypes !== null && contextTypes !== undefined; + context = isLegacyContextConsumer + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject; + } + + // Instantiate twice to help detect side-effects. + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + new ctor(props, context); // eslint-disable-line no-new + } + } + + var instance = new ctor(props, context); + var state = (workInProgress.memoizedState = + instance.state !== null && instance.state !== undefined + ? instance.state + : null); + adoptClassInstance(workInProgress, instance); + + { + if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); + warningWithoutStack$1( + false, + "`%s` uses `getDerivedStateFromProps` but its initial state is " + + "%s. This is not recommended. Instead, define the initial state by " + + "assigning an object to `this.state` in the constructor of `%s`. " + + "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", + componentName, + instance.state === null ? "null" : "undefined", + componentName + ); + } + } + + // If new component APIs are defined, "unsafe" lifecycles won't be called. + // Warn about these lifecycles if they are present. + // Don't warn about react-lifecycles-compat polyfilled methods though. + if ( + typeof ctor.getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function" + ) { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + foundWillMountName = "componentWillMount"; + } else if (typeof instance.UNSAFE_componentWillMount === "function") { + foundWillMountName = "UNSAFE_componentWillMount"; + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + foundWillReceivePropsName = "componentWillReceiveProps"; + } else if ( + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + foundWillUpdateName = "componentWillUpdate"; + } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { + foundWillUpdateName = "UNSAFE_componentWillUpdate"; + } + if ( + foundWillMountName !== null || + foundWillReceivePropsName !== null || + foundWillUpdateName !== null + ) { + var _componentName = getComponentName(ctor) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warningWithoutStack$1( + false, + "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + + "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + + "The above lifecycles should be removed. Learn more about this warning here:\n" + + "https://fb.me/react-async-component-lifecycle-hooks", + _componentName, + newApiName, + foundWillMountName !== null ? "\n " + foundWillMountName : "", + foundWillReceivePropsName !== null + ? "\n " + foundWillReceivePropsName + : "", + foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" + ); + } + } + } + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return instance; +} + +function callComponentWillMount(workInProgress, instance) { + startPhaseTimer(workInProgress, "componentWillMount"); + var oldState = instance.state; + + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + + stopPhaseTimer(); + + if (oldState !== instance.state) { + { + warningWithoutStack$1( + false, + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentName(workInProgress.type) || "Component" + ); + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, nextContext); + } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } + stopPhaseTimer(); + + if (instance.state !== oldState) { + { + var componentName = getComponentName(workInProgress.type) || "Component"; + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + warningWithoutStack$1( + false, + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +// Invokes the mount life-cycles on a previously never rendered instance. +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + { + checkClassInstance(workInProgress, ctor, newProps); + } + + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + + var contextType = ctor.contextType; + if (typeof contextType === "object" && contextType !== null) { + instance.context = readContext(contextType); + } else { + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); + } + + { + if (instance.state === newProps) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { + didWarnAboutDirectlyAssigningPropsToState.add(componentName); + warningWithoutStack$1( + false, + "%s: It is not recommended to assign props directly to state " + + "because updates to props won't be reflected in state. " + + "In most cases, it is better to use props directly.", + componentName + ); + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance + ); + + ReactStrictModeWarnings.recordLegacyContextWarning( + workInProgress, + instance + ); + } + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.recordDeprecationWarnings( + workInProgress, + instance + ); + } + } + + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + instance.state = workInProgress.memoizedState; + } + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + typeof ctor.getDerivedStateFromProps !== "function" && + typeof instance.getSnapshotBeforeUpdate !== "function" && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + callComponentWillMount(workInProgress, instance); + // If we had additional state updates during this life-cycle, let's + // process them now. + updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + } + + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } +} + +function resumeMountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextLegacyUnmaskedContext = getUnmaskedContext( + workInProgress, + ctor, + true + ); + nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + startPhaseTimer(workInProgress, "componentWillMount"); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +// Invokes the update life-cycles and returns false if it shouldn't rerender. +function updateClassInstance( + current, + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps); + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillUpdate === "function" || + typeof instance.componentWillUpdate === "function") + ) { + startPhaseTimer(workInProgress, "componentWillUpdate"); + if (typeof instance.componentWillUpdate === "function") { + instance.componentWillUpdate(newProps, newState, nextContext); + } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidUpdate === "function") { + workInProgress.effectTag |= Update; + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + workInProgress.effectTag |= Snapshot; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized props/state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +var didWarnAboutMaps = void 0; +var didWarnAboutGenerators = void 0; +var didWarnAboutStringRefInStrictMode = void 0; +var ownerHasKeyUseWarning = void 0; +var ownerHasFunctionTypeWarning = void 0; +var warnForMissingKey = function(child) {}; + +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefInStrictMode = {}; + + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + + warnForMissingKey = function(child) { + if (child === null || typeof child !== "object") { + return; + } + if (!child._store || child._store.validated || child.key != null) { + return; + } + (function() { + if (!(typeof child._store === "object")) { + throw ReactError( + "React Component in warnForMissingKey should have a _store. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + child._store.validated = true; + + var currentComponentErrorInfo = + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + + getCurrentFiberStackInDev(); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + ); + }; +} + +var isArray = Array.isArray; + +function coerceRef(returnFiber, current$$1, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if (returnFiber.mode & StrictMode) { + var componentName = getComponentName(returnFiber.type) || "Component"; + if (!didWarnAboutStringRefInStrictMode[componentName]) { + warningWithoutStack$1( + false, + 'A string ref, "%s", has been found within a strict mode tree. ' + + "String refs are a source of potential bugs and should be avoided. " + + "We recommend using createRef() instead." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-string-ref", + mixedRef, + getStackByFiberInDevAndProd(returnFiber) + ); + didWarnAboutStringRefInStrictMode[componentName] = true; + } + } + } + + if (element._owner) { + var owner = element._owner; + var inst = void 0; + if (owner) { + var ownerFiber = owner; + (function() { + if (!(ownerFiber.tag === ClassComponent)) { + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + } + })(); + inst = ownerFiber.stateNode; + } + (function() { + if (!inst) { + throw ReactError( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var stringRef = "" + mixedRef; + // Check if previous string ref matches new string ref + if ( + current$$1 !== null && + current$$1.ref !== null && + typeof current$$1.ref === "function" && + current$$1.ref._stringRef === stringRef + ) { + return current$$1.ref; + } + var ref = function(value) { + var refs = inst.refs; + if (refs === emptyRefsObject) { + // This is a lazy pooled frozen object, so we need to initialize. + refs = inst.refs = {}; + } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + ref._stringRef = stringRef; + return ref; + } else { + (function() { + if (!(typeof mixedRef === "string")) { + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } + })(); + (function() { + if (!element._owner) { + throw ReactError( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + })(); + } + } + return mixedRef; +} + +function throwOnInvalidObjectType(returnFiber, newChild) { + if (returnFiber.type !== "textarea") { + var addendum = ""; + { + addendum = + " If you meant to render a collection of children, use an array " + + "instead." + + getCurrentFiberStackInDev(); + } + (function() { + { + throw ReactError( + "Objects are not valid as a React child (found: " + + (Object.prototype.toString.call(newChild) === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + + addendum + ); + } + })(); + } +} + +function warnOnFunctionType() { + var currentComponentErrorInfo = + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + + getCurrentFiberStackInDev(); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); +} + +// This wrapper function exists because I expect to clone the code in each path +// to be able to optimize each path individually by branching early. This needs +// a compiler or we can do it manually. Helpers that don't need this branching +// live outside of this function. +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } + // Deletions are added in reversed order so we add it to the front. + // At this point, the return fiber's effect list is empty except for + // deletions, so we can just append the deletion to the list. The remaining + // effects aren't added until the complete phase. Once we implement + // resuming, this may not be true. + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } + childToDelete.nextEffect = null; + childToDelete.effectTag = Deletion; + } + + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } + + // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. + var childToDelete = currentFirstChild; + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } + return null; + } + + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + var existingChildren = new Map(); + + var existingChild = currentFirstChild; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } + existingChild = existingChild.sibling; + } + return existingChildren; + } + + function useFiber(fiber, pendingProps, expirationTime) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps, expirationTime); + clone.index = 0; + clone.sibling = null; + return clone; + } + + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) { + // Noop. + return lastPlacedIndex; + } + var current$$1 = newFiber.alternate; + if (current$$1 !== null) { + var oldIndex = current$$1.index; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } + } + + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.effectTag = Placement; + } + return newFiber; + } + + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (current$$1 === null || current$$1.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (current$$1 !== null && current$$1.elementType === element.type) { + // Move based on index + var existing = useFiber(current$$1, element.props, expirationTime); + existing.ref = coerceRef(returnFiber, current$$1, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + // Insert + var created = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + created.ref = coerceRef(returnFiber, current$$1, element); + created.return = returnFiber; + return created; + } + } + + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + current$$1 === null || + current$$1.tag !== HostPortal || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber( + current$$1, + portal.children || [], + expirationTime + ); + existing.return = returnFiber; + return existing; + } + } + + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (current$$1 === null || current$$1.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, fragment, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function createChild(returnFiber, newChild, expirationTime) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + expirationTime + ); + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; + } + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + _created2.return = returnFiber; + return _created2; + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + ); + _created3.return = returnFiber; + return _created3; + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + // Update the fiber if the keys match, otherwise return null. + + var key = oldFiber !== null ? oldFiber.key : null; + + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { + return null; + } + return updateTextNode( + returnFiber, + oldFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ); + } + return updateElement( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } + + return updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode( + returnFiber, + matchedFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + _matchedFiber, + newChild.props.children, + expirationTime, + newChild.key + ); + } + return updateElement( + returnFiber, + _matchedFiber, + newChild, + expirationTime + ); + } + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + return updatePortal( + returnFiber, + _matchedFiber2, + newChild, + expirationTime + ); + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + /** + * Warns if there is a duplicate or missing key + */ + function warnOnInvalidKey(child, knownKeys) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child); + var key = child.key; + if (typeof key !== "string") { + break; + } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } + warning$1( + false, + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key + ); + break; + default: + break; + } + } + return knownKeys; + } + + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. + + { + // First, validate keys. + var knownKeys = null; + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + ); + if (_newFiber === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } + previousNewFiber = _newFiber; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + ); + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } + previousNewFiber = _newFiber2; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + + var iteratorFn = getIteratorFn(newChildrenIterable); + (function() { + if (!(typeof iteratorFn === "function")) { + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && + // $FlowFixMe Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + !didWarnAboutGenerators + ? warning$1( + false, + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ) + : void 0; + didWarnAboutGenerators = true; + } + + // Warn about using Maps as children + if (newChildrenIterable.entries === iteratorFn) { + !didWarnAboutMaps + ? warning$1( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead." + ) + : void 0; + didWarnAboutMaps = true; + } + + // First, validate keys. + // We'll get a different iterator later for the main pass. + var _newChildren = iteratorFn.call(newChildrenIterable); + if (_newChildren) { + var knownKeys = null; + var _step = _newChildren.next(); + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + } + + var newChildren = iteratorFn.call(newChildrenIterable); + (function() { + if (!(newChildren != null)) { + throw ReactError("An iterable object provided no iterator."); + } + })(); + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + + var step = newChildren.next(); + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, expirationTime); + if (_newFiber3 === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } + previousNewFiber = _newFiber3; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + expirationTime + ); + if (_newFiber4 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber4.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber4.key === null ? newIdx : _newFiber4.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } + previousNewFiber = _newFiber4; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + expirationTime + ) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + // The existing first child is not a text node so we need to create one + // and delete the existing ones. + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + expirationTime + ) { + var key = element.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === Fragment + ? element.type === REACT_FRAGMENT_TYPE + : child.elementType === element.type + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber( + child, + element.type === REACT_FRAGMENT_TYPE + ? element.props.children + : element.props, + expirationTime + ); + existing.ref = coerceRef(returnFiber, child, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + expirationTime, + element.key + ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } + + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + expirationTime + ) { + var key = portal.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === HostPortal && + child.stateNode.containerInfo === portal.containerInfo && + child.stateNode.implementation === portal.implementation + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || [], expirationTime); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } + + // Handle object types + var isObject = typeof newChild === "object" && newChild !== null; + + if (isObject) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + } + } + + if (typeof newChild === "string" || typeof newChild === "number") { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + expirationTime + ) + ); + } + + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (isObject) { + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + if (typeof newChild === "undefined" && !isUnkeyedTopLevelFragment) { + // If the new child is undefined, and the return fiber is a composite + // component, throw an error. If Fiber return types are disabled, + // we already threw above. + switch (returnFiber.tag) { + case ClassComponent: { + { + var instance = returnFiber.stateNode; + if (instance.render._isMockFunction) { + // We allow auto-mocks to proceed as if they're returning null. + break; + } + } + } + // Intentionally fall through to the next case, which handles both + // functions and classes + // eslint-disable-next-lined no-fallthrough + case FunctionComponent: { + var Component = returnFiber.type; + (function() { + { + throw ReactError( + (Component.displayName || Component.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + ); + } + })(); + } + } + } + + // Remaining cases are all treated as empty. + return deleteRemainingChildren(returnFiber, currentFirstChild); + } + + return reconcileChildFibers; +} + +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); + +function cloneChildFibers(current$$1, workInProgress) { + (function() { + if (!(current$$1 === null || workInProgress.child === current$$1.child)) { + throw ReactError("Resuming work not yet implemented."); + } + })(); + + if (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + workInProgress.child = newChild; + + newChild.return = workInProgress; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + newChild.return = workInProgress; + } + newChild.sibling = null; +} + +var NO_CONTEXT = {}; + +var contextStackCursor$1 = createCursor(NO_CONTEXT); +var contextFiberStackCursor = createCursor(NO_CONTEXT); +var rootInstanceStackCursor = createCursor(NO_CONTEXT); + +function requiredContext(c) { + (function() { + if (!(c !== NO_CONTEXT)) { + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + return c; +} + +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} + +function pushHostContainer(fiber, nextRootInstance) { + // Push current root instance onto the stack; + // This allows us to reset root when portals are popped. + push(rootInstanceStackCursor, nextRootInstance, fiber); + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + + // Finally, we need to push the host context to the stack. + // However, we can't just call getRootHostContext() and push it because + // we'd have a different number of entries on the stack depending on + // whether getRootHostContext() throws somewhere in renderer code or not. + // So we push an empty value first. This lets us safely unwind on errors. + push(contextStackCursor$1, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, nextRootContext, fiber); +} + +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} + +function getHostContext() { + var context = requiredContext(contextStackCursor$1.current); + return context; +} + +function pushHostContext(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContext(context, fiber.type, rootInstance); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventComponent(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContextForEventComponent(context); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventTarget(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var eventTargetType = fiber.type.type; + var nextContext = getChildHostContextForEventTarget(context, eventTargetType); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function popHostContext(fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + if (contextFiberStackCursor.current !== fiber) { + return; + } + + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); +} + +var NoEffect$1 = /* */ 0; +var UnmountSnapshot = /* */ 2; +var UnmountMutation = /* */ 4; +var MountMutation = /* */ 8; +var UnmountLayout = /* */ 16; +var MountLayout = /* */ 32; +var MountPassive = /* */ 64; +var UnmountPassive = /* */ 128; + +var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; + +var didWarnAboutMismatchedHooksForComponent = void 0; +{ + didWarnAboutMismatchedHooksForComponent = new Set(); +} + +// These are set right before calling the component. +var renderExpirationTime$1 = NoWork; +// The work-in-progress fiber. I've named it differently to distinguish it from +// the work-in-progress hook. +var currentlyRenderingFiber$1 = null; + +// Hooks are stored as a linked list on the fiber's memoizedState field. The +// current hook list is the list that belongs to the current fiber. The +// work-in-progress hook list is a new list that will be added to the +// work-in-progress fiber. +var currentHook = null; +var nextCurrentHook = null; +var firstWorkInProgressHook = null; +var workInProgressHook = null; +var nextWorkInProgressHook = null; + +var remainingExpirationTime = NoWork; +var componentUpdateQueue = null; +var sideEffectTag = 0; + +// Updates scheduled during render will trigger an immediate re-render at the +// end of the current pass. We can't store these updates on the normal queue, +// because if the work is aborted, they should be discarded. Because this is +// a relatively rare case, we also don't want to add an additional field to +// either the hook or queue object types. So we store them in a lazily create +// map of queue -> render-phase updates, which are discarded once the component +// completes without re-rendering. + +// Whether an update was scheduled during the currently executing render pass. +var didScheduleRenderPhaseUpdate = false; +// Lazily created map of render-phase updates +var renderPhaseUpdates = null; +// Counter to prevent infinite loops. +var numberOfReRenders = 0; +var RE_RENDER_LIMIT = 25; + +// In DEV, this is the name of the currently executing primitive hook +var currentHookNameInDev = null; + +// In DEV, this list ensures that hooks are called in the same order between renders. +// The list stores the order of hooks used during the initial render (mount). +// Subsequent renders (updates) reference this list. +var hookTypesDev = null; +var hookTypesUpdateIndexDev = -1; + +function mountHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev === null) { + hookTypesDev = [hookName]; + } else { + hookTypesDev.push(hookName); + } + } +} + +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } + } + } +} + +function checkDepsAreArrayDev(deps) { + { + if (deps !== undefined && deps !== null && !Array.isArray(deps)) { + // Verify deps, but only on mount to avoid extra checks. + // It's unlikely their type would change as usually you define them inline. + warning$1( + false, + "%s received a final argument that is not an array (instead, received `%s`). When " + + "specified, the final argument must be an array.", + currentHookNameInDev, + typeof deps + ); + } + } +} + +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentName(currentlyRenderingFiber$1.type); + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); + + if (hookTypesDev !== null) { + var table = ""; + + var secondColumnStart = 30; + + for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { + var oldHookName = hookTypesDev[i]; + var newHookName = + i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; + + var row = i + 1 + ". " + oldHookName; + + // Extra space so second column lines up + // lol @ IE not supporting String#repeat + while (row.length < secondColumnStart) { + row += " "; + } + + row += newHookName + "\n"; + + table += row; + } + + warning$1( + false, + "React has detected a change in the order of Hooks called by %s. " + + "This will lead to bugs and errors if not fixed. " + + "For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n" + + " Previous render Next render\n" + + " ------------------------------------------------------\n" + + "%s" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + componentName, + table + ); + } + } + } +} + +function throwInvalidHookError() { + (function() { + { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); + } + })(); +} + +function areHookInputsEqual(nextDeps, prevDeps) { + if (prevDeps === null) { + { + warning$1( + false, + "%s received a final argument during this render, but not during " + + "the previous render. Even though the final argument is optional, " + + "its type cannot change between renders.", + currentHookNameInDev + ); + } + return false; + } + + { + // Don't bother comparing lengths in prod because these arrays should be + // passed inline. + if (nextDeps.length !== prevDeps.length) { + warning$1( + false, + "The final argument passed to %s changed size between renders. The " + + "order and size of this array must remain constant.\n\n" + + "Previous: %s\n" + + "Incoming: %s", + currentHookNameInDev, + "[" + prevDeps.join(", ") + "]", + "[" + nextDeps.join(", ") + "]" + ); + } + } + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { + if (is(nextDeps[i], prevDeps[i])) { + continue; + } + return false; + } + return true; +} + +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = current !== null ? current.memoizedState : null; + + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; + } + + // The following should have already been reset + // currentHook = null; + // workInProgressHook = null; + + // remainingExpirationTime = NoWork; + // componentUpdateQueue = null; + + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + // sideEffectTag = 0; + + // TODO Warn if no hooks are used at all during mount, then some are used during update. + // Currently we will identify the update render as a mount because nextCurrentHook === null. + // This is tricky because it's valid for certain types of components (e.g. React.lazy) + + // Using nextCurrentHook to differentiate between mount/update only works if at least one stateful hook is used. + // Non-stateful hooks (e.g. context) don't get added to memoizedState, + // so nextCurrentHook would be null during updates and mounts. + { + if (nextCurrentHook !== null) { + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + } else if (hookTypesDev !== null) { + // This dispatcher handles an edge case where a component is updating, + // but no stateful hooks have been used. + // We want to match the production code behavior (which will use HooksDispatcherOnMount), + // but with the extra DEV validation to ensure hooks ordering hasn't changed. + // This dispatcher does that. + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + } + } + + var children = Component(props, refOrContext); + + if (didScheduleRenderPhaseUpdate) { + do { + didScheduleRenderPhaseUpdate = false; + numberOfReRenders += 1; + + // Start over from the beginning of the list + nextCurrentHook = current !== null ? current.memoizedState : null; + nextWorkInProgressHook = firstWorkInProgressHook; + + currentHook = null; + workInProgressHook = null; + componentUpdateQueue = null; + + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; + } + + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + + children = Component(props, refOrContext); + } while (didScheduleRenderPhaseUpdate); + + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + var renderedWork = currentlyRenderingFiber$1; + + renderedWork.memoizedState = firstWorkInProgressHook; + renderedWork.expirationTime = remainingExpirationTime; + renderedWork.updateQueue = componentUpdateQueue; + renderedWork.effectTag |= sideEffectTag; + + { + renderedWork._debugHookTypes = hookTypesDev; + } + + // This check uses currentHook so that it works the same in DEV and prod bundles. + // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + currentHookNameInDev = null; + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + // These were reset above + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + + (function() { + if (!!didRenderTooFewHooks) { + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + } + })(); + + return children; +} + +function bailoutHooks(current, workInProgress, expirationTime) { + workInProgress.updateQueue = current.updateQueue; + workInProgress.effectTag &= ~(Passive | Update); + if (current.expirationTime <= expirationTime) { + current.expirationTime = NoWork; + } +} + +function resetHooks() { + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + // This is used to reset the state of this module when a component throws. + // It's also called inside mountIndeterminateComponent if we determine the + // component is a module-style component. + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + + currentHookNameInDev = null; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + didScheduleRenderPhaseUpdate = false; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} + +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + + baseState: null, + queue: null, + baseUpdate: null, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list + firstWorkInProgressHook = workInProgressHook = hook; + } else { + // Append to the end of the list + workInProgressHook = workInProgressHook.next = hook; + } + return workInProgressHook; +} + +function updateWorkInProgressHook() { + // This function is used both for updates and for re-renders triggered by a + // render phase update. It assumes there is either a current hook we can + // clone, or a work-in-progress hook from a previous render pass that we can + // use as a base. When we reach the end of the base list, we must switch to + // the dispatcher used for mounts. + if (nextWorkInProgressHook !== null) { + // There's already a work-in-progress. Reuse it. + workInProgressHook = nextWorkInProgressHook; + nextWorkInProgressHook = workInProgressHook.next; + + currentHook = nextCurrentHook; + nextCurrentHook = currentHook !== null ? currentHook.next : null; + } else { + // Clone from the current hook. + (function() { + if (!(nextCurrentHook !== null)) { + throw ReactError( + "Rendered more hooks than during the previous render." + ); + } + })(); + currentHook = nextCurrentHook; + + var newHook = { + memoizedState: currentHook.memoizedState, + + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list. + workInProgressHook = firstWorkInProgressHook = newHook; + } else { + // Append to the end of the list. + workInProgressHook = workInProgressHook.next = newHook; + } + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} + +function createFunctionComponentUpdateQueue() { + return { + lastEffect: null + }; +} + +function basicStateReducer(state, action) { + return typeof action === "function" ? action(state) : action; +} + +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState = void 0; + if (init !== undefined) { + initialState = init(initialArg); + } else { + initialState = initialArg; + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; + (function() { + if (!(queue !== null)) { + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + } + })(); + + queue.lastRenderedReducer = reducer; + + if (numberOfReRenders > 0) { + // This is a re-render. Apply the new render phase updates to the previous + var _dispatch = queue.dispatch; + if (renderPhaseUpdates !== null) { + // Render phase updates are stored in a map of queue -> linked list + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate !== undefined) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + var update = firstRenderPhaseUpdate; + do { + // Process this render phase update. We don't have to check the + // priority because it will always be the same as the current + // render's. + var _action = update.action; + newState = reducer(newState, _action); + update = update.next; + } while (update !== null); + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = newState; + // Don't persist the state accumlated from the render phase updates to + // the base state unless the queue is empty. + // TODO: Not sure if this is the desired semantics, but it's what we + // do for gDSFP. I can't remember why. + if (hook.baseUpdate === queue.last) { + hook.baseState = newState; + } + + queue.lastRenderedState = newState; + + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + + // The last update in the entire queue + var last = queue.last; + // The last update that is part of the base state. + var baseUpdate = hook.baseUpdate; + var baseState = hook.baseState; + + // Find the first unprocessed update. + var first = void 0; + if (baseUpdate !== null) { + if (last !== null) { + // For the first update, the queue is a circular linked list where + // `queue.last.next = queue.first`. Once the first update commits, and + // the `baseUpdate` is no longer empty, we can unravel the list. + last.next = null; + } + first = baseUpdate.next; + } else { + first = last !== null ? last.next : null; + } + if (first !== null) { + var _newState = baseState; + var newBaseState = null; + var newBaseUpdate = null; + var prevUpdate = baseUpdate; + var _update = first; + var didSkip = false; + do { + var updateExpirationTime = _update.expirationTime; + if (updateExpirationTime < renderExpirationTime$1) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + if (!didSkip) { + didSkip = true; + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + // Update the remaining priority in the queue. + if (updateExpirationTime > remainingExpirationTime) { + remainingExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process this update. + if (_update.eagerReducer === reducer) { + // If this update was processed eagerly, and its reducer matches the + // current reducer, we can use the eagerly computed state. + _newState = _update.eagerState; + } else { + var _action2 = _update.action; + _newState = reducer(_newState, _action2); + } + } + prevUpdate = _update; + _update = _update.next; + } while (_update !== null && _update !== first); + + if (!didSkip) { + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(_newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = _newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = newBaseState; + + queue.lastRenderedState = _newState; + } + + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} + +function mountState(initialState) { + var hook = mountWorkInProgressHook(); + if (typeof initialState === "function") { + initialState = initialState(); + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateState(initialState) { + return updateReducer(basicStateReducer, initialState); +} + +function pushEffect(tag, create, destroy, deps) { + var effect = { + tag: tag, + create: create, + destroy: destroy, + deps: deps, + // Circular + next: null + }; + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var _lastEffect = componentUpdateQueue.lastEffect; + if (_lastEffect === null) { + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var firstEffect = _lastEffect.next; + _lastEffect.next = effect; + effect.next = firstEffect; + componentUpdateQueue.lastEffect = effect; + } + } + return effect; +} + +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { current: initialValue }; + { + Object.seal(ref); + } + hook.memoizedState = ref; + return ref; +} + +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} + +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); +} + +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var destroy = undefined; + + if (currentHook !== null) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (nextDeps !== null) { + var prevDeps = prevEffect.deps; + if (areHookInputsEqual(nextDeps, prevDeps)) { + pushEffect(NoEffect$1, create, destroy, nextDeps); + return; + } + } + } + + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); +} + +function mountEffect(create, deps) { + return mountEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function updateEffect(create, deps) { + return updateEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function mountLayoutEffect(create, deps) { + return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function imperativeHandleEffect(create, ref) { + if (typeof ref === "function") { + var refCallback = ref; + var _inst = create(); + refCallback(_inst); + return function() { + refCallback(null); + }; + } else if (ref !== null && ref !== undefined) { + var refObject = ref; + { + !refObject.hasOwnProperty("current") + ? warning$1( + false, + "Expected useImperativeHandle() first argument to either be a " + + "ref callback or React.createRef() object. Instead received: %s.", + "an object with keys {" + Object.keys(refObject).join(", ") + "}" + ) + : void 0; + } + var _inst2 = create(); + refObject.current = _inst2; + return function() { + refObject.current = null; + }; + } +} + +function mountImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return mountEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function updateImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return updateEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function mountDebugValue(value, formatterFn) { + // This hook is normally a no-op. + // The react-debug-hooks package injects its own implementation + // so that e.g. DevTools can display custom hook values. +} + +var updateDebugValue = mountDebugValue; + +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function updateMemo(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + // Assume these are defined. If they're not, areHookInputsEqual will warn. + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function dispatchAction(fiber, queue, action) { + (function() { + if (!(numberOfReRenders < RE_RENDER_LIMIT)) { + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + } + })(); + + { + !(arguments.length <= 3) + ? warning$1( + false, + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." + ) + : void 0; + } + + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (alternate !== null && alternate === currentlyRenderingFiber$1) + ) { + // This is a render phase update. Stash it in a lazily-created map of + // queue -> linked list of updates. After this render pass, we'll restart + // and apply the stashed updates on top of the work-in-progress hook. + didScheduleRenderPhaseUpdate = true; + var update = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + if (renderPhaseUpdates === null) { + renderPhaseUpdates = new Map(); + } + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate === undefined) { + renderPhaseUpdates.set(queue, update); + } else { + // Append the update to the end of the list. + var lastRenderPhaseUpdate = firstRenderPhaseUpdate; + while (lastRenderPhaseUpdate.next !== null) { + lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; + } + lastRenderPhaseUpdate.next = update; + } + } else { + flushPassiveEffects(); + + var currentTime = requestCurrentTime(); + var _expirationTime = computeExpirationForFiber(currentTime, fiber); + + var _update2 = { + expirationTime: _expirationTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + + // Append the update to the end of the list. + var _last = queue.last; + if (_last === null) { + // This is the first update. Create a circular list. + _update2.next = _update2; + } else { + var first = _last.next; + if (first !== null) { + // Still circular. + _update2.next = first; + } + _last.next = _update2; + } + queue.last = _update2; + + if ( + fiber.expirationTime === NoWork && + (alternate === null || alternate.expirationTime === NoWork) + ) { + // The queue is currently empty, which means we can eagerly compute the + // next state before entering the render phase. If the new state is the + // same as the current state, we may be able to bail out entirely. + var _lastRenderedReducer = queue.lastRenderedReducer; + if (_lastRenderedReducer !== null) { + var prevDispatcher = void 0; + { + prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + } + try { + var currentState = queue.lastRenderedState; + var _eagerState = _lastRenderedReducer(currentState, action); + // Stash the eagerly computed state, and the reducer used to compute + // it, on the update object. If the reducer hasn't changed by the + // time we enter the render phase, then the eager state can be used + // without calling the reducer again. + _update2.eagerReducer = _lastRenderedReducer; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) { + // Fast path. We can bail out without scheduling React to re-render. + // It's still possible that we'll need to rebase this update later, + // if the component re-renders for a different reason and by that + // time the reducer has changed. + return; + } + } catch (error) { + // Suppress the error. It will throw again in the render phase. + } finally { + { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + } + } + } + { + // jest isn't a 'global', it's just exposed to tests via a wrapped function + // further, this isn't a test file, so flow doesn't recognize the symbol. So... + // $FlowExpectedError - because requirements don't give a damn about your type sigs. + if ("undefined" !== typeof jest) { + warnIfNotCurrentlyActingUpdatesInDev(fiber); + } + } + scheduleWork(fiber, _expirationTime); + } +} + +var ContextOnlyDispatcher = { + readContext: readContext, + + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError +}; + +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; + +{ + var warnInvalidContextAccess = function() { + warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + }; + + var warnInvalidHookAccess = function() { + warning$1( + false, + "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + + "You can only call Hooks at the top level of your React function. " + + "For more information, see " + + "https://fb.me/rules-of-hooks" + ); + }; + + HooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; +} + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var now$1 = Scheduler.unstable_now; + +var commitTime = 0; +var profilerStartTime = -1; + +function getCommitTime() { + return commitTime; +} + +function recordCommitTime() { + if (!enableProfilerTimer) { + return; + } + commitTime = now$1(); +} + +function startProfilerTimer(fiber) { + if (!enableProfilerTimer) { + return; + } + + profilerStartTime = now$1(); + + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now$1(); + } +} + +function stopProfilerTimerIfRunning(fiber) { + if (!enableProfilerTimer) { + return; + } + profilerStartTime = -1; +} + +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (!enableProfilerTimer) { + return; + } + + if (profilerStartTime >= 0) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; + } + profilerStartTime = -1; + } +} + +// The deepest Fiber on the stack involved in a hydration context. +// This may have been an insertion or a hydration. +var hydrationParentFiber = null; +var nextHydratableInstance = null; +var isHydrating = false; + +function enterHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = getFirstHydratableChild(parentInstance); + hydrationParentFiber = fiber; + isHydrating = true; + return true; +} + +function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + return false; + } + + var suspenseInstance = fiber.stateNode; + nextHydratableInstance = getNextHydratableSibling(suspenseInstance); + popToNextHostParent(fiber); + isHydrating = true; + return true; +} + +function deleteHydratableInstance(returnFiber, instance) { + { + switch (returnFiber.tag) { + case HostRoot: + didNotHydrateContainerInstance( + returnFiber.stateNode.containerInfo, + instance + ); + break; + case HostComponent: + didNotHydrateInstance( + returnFiber.type, + returnFiber.memoizedProps, + returnFiber.stateNode, + instance + ); + break; + } + } + + var childToDelete = createFiberFromHostInstanceForDeletion(); + childToDelete.stateNode = instance; + childToDelete.return = returnFiber; + childToDelete.effectTag = Deletion; + + // This might seem like it belongs on progressedFirstDeletion. However, + // these children are not part of the reconciliation list of children. + // Even if we abort and rereconcile the children, that will try to hydrate + // again and the nodes are still in the host tree so these will be + // recreated. + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } +} + +function insertNonHydratedInstance(returnFiber, fiber) { + fiber.effectTag |= Placement; + { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + switch (fiber.tag) { + case HostComponent: + var type = fiber.type; + var props = fiber.pendingProps; + didNotFindHydratableContainerInstance(parentContainer, type, props); + break; + case HostText: + var text = fiber.pendingProps; + didNotFindHydratableContainerTextInstance(parentContainer, text); + break; + case SuspenseComponent: + didNotFindHydratableContainerSuspenseInstance(parentContainer); + break; + } + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + switch (fiber.tag) { + case HostComponent: + var _type = fiber.type; + var _props = fiber.pendingProps; + didNotFindHydratableInstance( + parentType, + parentProps, + parentInstance, + _type, + _props + ); + break; + case HostText: + var _text = fiber.pendingProps; + didNotFindHydratableTextInstance( + parentType, + parentProps, + parentInstance, + _text + ); + break; + case SuspenseComponent: + didNotFindHydratableSuspenseInstance( + parentType, + parentProps, + parentInstance + ); + break; + } + break; + } + default: + return; + } + } +} + +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case HostComponent: { + var type = fiber.type; + var props = fiber.pendingProps; + var instance = canHydrateInstance(nextInstance, type, props); + if (instance !== null) { + fiber.stateNode = instance; + return true; + } + return false; + } + case HostText: { + var text = fiber.pendingProps; + var textInstance = canHydrateTextInstance(nextInstance, text); + if (textInstance !== null) { + fiber.stateNode = textInstance; + return true; + } + return false; + } + case SuspenseComponent: { + if (enableSuspenseServerRenderer) { + var suspenseInstance = canHydrateSuspenseInstance(nextInstance); + if (suspenseInstance !== null) { + // Downgrade the tag to a dehydrated component until we've hydrated it. + fiber.tag = DehydratedSuspenseComponent; + fiber.stateNode = suspenseInstance; + return true; + } + } + return false; + } + default: + return false; + } +} + +function tryToClaimNextHydratableInstance(fiber) { + if (!isHydrating) { + return; + } + var nextInstance = nextHydratableInstance; + if (!nextInstance) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber, nextInstance)) { + // If we can't hydrate this instance let's try the next one. + // We use this as a heuristic. It's based on intuition and not data so it + // might be flawed or unnecessary. + nextInstance = getNextHydratableSibling(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + // We matched the next one, we'll now assume that the first one was + // superfluous and we'll delete it. Since we can't eagerly delete it + // we'll have to schedule a deletion. To do that, this node needs a dummy + // fiber associated with it. + deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); +} + +function prepareToHydrateHostInstance( + fiber, + rootContainerInstance, + hostContext +) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var instance = fiber.stateNode; + var updatePayload = hydrateInstance( + instance, + fiber.type, + fiber.memoizedProps, + rootContainerInstance, + hostContext, + fiber + ); + // TODO: Type this specific to this type of component. + fiber.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. + if (updatePayload !== null) { + return true; + } + return false; +} + +function prepareToHydrateHostTextInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var textInstance = fiber.stateNode; + var textContent = fiber.memoizedProps; + var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); + { + if (shouldUpdate) { + // We assume that prepareToHydrateHostTextInstance is called in a context where the + // hydration parent is the parent host component of this host text. + var returnFiber = hydrationParentFiber; + if (returnFiber !== null) { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + didNotMatchHydratedContainerTextInstance( + parentContainer, + textInstance, + textContent + ); + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + didNotMatchHydratedTextInstance( + parentType, + parentProps, + parentInstance, + textInstance, + textContent + ); + break; + } + } + } + } + } + return shouldUpdate; +} + +function skipPastDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected skipPastDehydratedSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + var suspenseInstance = fiber.stateNode; + (function() { + if (!suspenseInstance) { + throw ReactError( + "Expected to have a hydrated suspense instance. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance( + suspenseInstance + ); +} + +function popToNextHostParent(fiber) { + var parent = fiber.return; + while ( + parent !== null && + parent.tag !== HostComponent && + parent.tag !== HostRoot && + parent.tag !== DehydratedSuspenseComponent + ) { + parent = parent.return; + } + hydrationParentFiber = parent; +} + +function popHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + if (fiber !== hydrationParentFiber) { + // We're deeper than the current hydration context, inside an inserted + // tree. + return false; + } + if (!isHydrating) { + // If we're not currently hydrating but we're in a hydration context, then + // we were an insertion and now need to pop up reenter hydration of our + // siblings. + popToNextHostParent(fiber); + isHydrating = true; + return false; + } + + var type = fiber.type; + + // If we have any remaining hydratable nodes, we need to delete them now. + // We only do this deeper than head and body since they tend to have random + // other nodes in them. We also ignore components with pure text content in + // side of them. + // TODO: Better heuristic. + if ( + fiber.tag !== HostComponent || + (type !== "head" && + type !== "body" && + !shouldSetTextContent(type, fiber.memoizedProps)) + ) { + var nextInstance = nextHydratableInstance; + while (nextInstance) { + deleteHydratableInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); + } + } + + popToNextHostParent(fiber); + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; + return true; +} + +function resetHydrationState() { + if (!supportsHydration) { + return; + } + + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; +} + +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; + +var didReceiveUpdate = false; + +var didWarnAboutBadClass = void 0; +var didWarnAboutModulePatternComponent = void 0; +var didWarnAboutContextTypeOnFunctionComponent = void 0; +var didWarnAboutGetDerivedStateOnFunctionComponent = void 0; +var didWarnAboutFunctionRefs = void 0; +var didWarnAboutReassigningProps = void 0; +var didWarnAboutMaxDuration = void 0; + +{ + didWarnAboutBadClass = {}; + didWarnAboutModulePatternComponent = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutMaxDuration = false; +} + +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + if (current$$1 === null) { + // If this is a fresh new component that hasn't been rendered yet, we + // won't update its child set by applying minimal side-effects. Instead, + // we will add them all to the child before it gets rendered. That means + // we can optimize this reconciliation pass by not tracking side-effects. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // If the current child is the same as the work in progress, it means that + // we haven't yet started any work on these children. Therefore, we use + // the clone algorithm to create a copy of all the current children. + + // If we had any progressed work already, that is invalid at this point so + // let's throw it out. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); + } +} + +function forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + // This function is fork of reconcileChildren. It's used in cases where we + // want to reconcile without matching against the existing set. This has the + // effect of all current children being unmounted; even if the type and key + // are the same, the old child is unmounted and a new child is created. + // + // To do this, we're going to go through the reconcile algorithm twice. In + // the first pass, we schedule a deletion for all the current children by + // passing null. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + ); + // In the second pass, we mount the new children. The trick here is that we + // pass null in place of where we usually pass the current child set. This has + // the effect of remounting all children regardless of whether their their + // identity matches. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); +} + +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens after the first render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var render = Component.render; + var ref = workInProgress.ref; + + // The rest is a fork of updateFunctionComponent + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (current$$1 === null) { + var type = Component.type; + if ( + isSimpleFunctionComponent(type) && + Component.compare === null && + // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined + ) { + // If this is a plain function component without default props, + // and with only the default shallow comparison, we upgrade it + // to a SimpleMemoComponent to allow fast path updates. + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = type; + { + validateFunctionComponentInDev(workInProgress, type); + } + return updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ); + } + { + var innerPropTypes = type.propTypes; + if (innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(type), + getCurrentFiberStackInDev + ); + } + } + var child = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } + { + var _type = Component.type; + var _innerPropTypes = _type.propTypes; + if (_innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + _innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(_type), + getCurrentFiberStackInDev + ); + } + } + var currentChild = current$$1.child; // This is always exactly one child + if (updateExpirationTime < renderExpirationTime) { + // This will be the props with resolved defaultProps, + // unlike current.memoizedProps which will be the unresolved ones. + var prevProps = currentChild.memoizedProps; + // Default to shallow comparison + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; + if ( + compare(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + var newChild = createWorkInProgress( + currentChild, + nextProps, + renderExpirationTime + ); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} + +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens when the inner render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var outerMemoType = workInProgress.elementType; + if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { + // We warn when you define propTypes on lazy() + // so let's just skip over it to find memo() outer wrapper. + // Inner props for memo are validated later. + outerMemoType = refineResolvedLazyComponent(outerMemoType); + } + var outerPropTypes = outerMemoType && outerMemoType.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + nextProps, // Resolved (SimpleMemoComponent has no defaultProps) + "prop", + getComponentName(outerMemoType), + getCurrentFiberStackInDev + ); + } + // Inner propTypes will be validated in the function component path. + } + } + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + if ( + shallowEqual(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + didReceiveUpdate = false; + if (updateExpirationTime < renderExpirationTime) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + } + return updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} + +function updateFragment(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMode(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateProfiler(current$$1, workInProgress, renderExpirationTime) { + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (current$$1 === null && ref !== null) || + (current$$1 !== null && current$$1.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.effectTag |= Ref; + } +} + +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + var instance = workInProgress.stateNode; + var shouldUpdate = void 0; + if (instance === null) { + if (current$$1 !== null) { + // An class component without an instance only mounts if it suspended + // inside a non- concurrent tree, in an inconsistent state. We want to + // tree it like a new mount, even though an empty version of it already + // committed. Disconnect the alternate pointers. + current$$1.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + // In the initial pass we might need to construct the instance. + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + shouldUpdate = true; + } else if (current$$1 === null) { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } else { + shouldUpdate = updateClassInstance( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } + var nextUnitOfWork = finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime + ); + { + var inst = workInProgress.stateNode; + if (inst.props !== nextProps) { + !didWarnAboutReassigningProps + ? warning$1( + false, + "It looks like %s is reassigning its own `this.props` while rendering. " + + "This is not supported and can lead to confusing bugs.", + getComponentName(workInProgress.type) || "a component" + ) + : void 0; + didWarnAboutReassigningProps = true; + } + } + return nextUnitOfWork; +} + +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current$$1, workInProgress); + + var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; + + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); + } + + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + var instance = workInProgress.stateNode; + + // Rerender + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = void 0; + if ( + didCaptureError && + typeof Component.getDerivedStateFromError !== "function" + ) { + // If we captured an error, but getDerivedStateFrom catch is not defined, + // unmount all the children. componentDidCatch will schedule an update to + // re-render a fallback. This is temporary until we migrate everyone to + // the new API. + // TODO: Warn in a future release. + nextChildren = null; + + if (enableProfilerTimer) { + stopProfilerTimerIfRunning(workInProgress); + } + } else { + { + setCurrentPhase("render"); + nextChildren = instance.render(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + instance.render(); + } + setCurrentPhase(null); + } + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + if (current$$1 !== null && didCaptureError) { + // If we're recovering from an error, reconcile without reusing any of + // the existing children. Conceptually, the normal children and the children + // that are shown on error are two different sets, so we shouldn't reuse + // normal children even if their identities match. + forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + + // Memoize state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. + workInProgress.memoizedState = instance.state; + + // The context might have changed so we need to recalculate it. + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } + + return workInProgress.child; +} + +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + if (root.pendingContext) { + pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } + pushHostContainer(workInProgress, root.containerInfo); +} + +function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { + pushHostRootContext(workInProgress); + var updateQueue = workInProgress.updateQueue; + (function() { + if (!(updateQueue !== null)) { + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState !== null ? prevState.element : null; + processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + null, + renderExpirationTime + ); + var nextState = workInProgress.memoizedState; + // Caution: React DevTools currently depends on this property + // being called "element". + var nextChildren = nextState.element; + if (nextChildren === prevChildren) { + // If the state is the same as before, that's a bailout because we had + // no work that expires at this time. + resetHydrationState(); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + var root = workInProgress.stateNode; + if ( + (current$$1 === null || current$$1.child === null) && + root.hydrate && + enterHydrationState(workInProgress) + ) { + // If we don't have any current children this might be the first pass. + // We always try to hydrate. If this isn't a hydration pass there won't + // be any children to hydrate which is effectively the same thing as + // not hydrating. + + // This is a bit of a hack. We track the host root as a placement to + // know that we're currently in a mounting state. That way isMounted + // works as expected. We must reset this before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag |= Placement; + + // Ensure that children mount into this root without tracking + // side-effects. This ensures that we don't store Placement effects on + // nodes that will be hydrated. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // Otherwise reset hydration state in case we aborted and resumed another + // root. + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + resetHydrationState(); + } + return workInProgress.child; +} + +function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { + pushHostContext(workInProgress); + + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var nextProps = workInProgress.pendingProps; + var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; + + var nextChildren = nextProps.children; + var isDirectTextChild = shouldSetTextContent(type, nextProps); + + if (isDirectTextChild) { + // We special case a direct text child of a host node. This is a common + // case. We won't handle it as a reified child. We will instead handle + // this in the host environment that also have access to this prop. That + // avoids allocating another HostText fiber and traversing it. + nextChildren = null; + } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { + // If we're switching from a direct text child to a normal child, or to + // empty, we need to schedule the text content to be reset. + workInProgress.effectTag |= ContentReset; + } + + markRef(current$$1, workInProgress); + + // Check the host config to see if the children are offscreen/hidden. + if ( + renderExpirationTime !== Never && + workInProgress.mode & ConcurrentMode && + shouldDeprioritizeSubtree(type, nextProps) + ) { + // Schedule this fiber to re-render at offscreen priority. Then bailout. + workInProgress.expirationTime = workInProgress.childExpirationTime = Never; + return null; + } + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateHostText(current$$1, workInProgress) { + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + return null; +} + +function mountLazyComponent( + _current, + workInProgress, + elementType, + updateExpirationTime, + renderExpirationTime +) { + if (_current !== null) { + // An lazy component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + // We can't start a User Timing measurement with correct label yet. + // Cancel and resume right after we know the tag. + cancelWorkTimer(workInProgress); + var Component = readLazyComponentType(elementType); + // Store the unwrapped component in the type. + workInProgress.type = Component; + var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); + startWorkTimer(workInProgress); + var resolvedProps = resolveDefaultProps(Component, props); + var child = void 0; + switch (resolvedTag) { + case FunctionComponent: { + { + validateFunctionComponentInDev(workInProgress, Component); + } + child = updateFunctionComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ClassComponent: { + child = updateClassComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ForwardRef: { + child = updateForwardRef( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case MemoComponent: { + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = Component.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + resolvedProps, // Resolved for outer only + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + child = updateMemoComponent( + null, + workInProgress, + Component, + resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too + updateExpirationTime, + renderExpirationTime + ); + break; + } + default: { + var hint = ""; + { + if ( + Component !== null && + typeof Component === "object" && + Component.$$typeof === REACT_LAZY_TYPE + ) { + hint = " Did you wrap a component in React.lazy() more than once?"; + } + } + // This message intentionally doesn't mention ForwardRef or MemoComponent + // because the fact that it's a separate type of work is an + // implementation detail. + (function() { + { + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + Component + + ". Lazy element type must resolve to a class or function." + + hint + ); + } + })(); + } + } + return child; +} + +function mountIncompleteClassComponent( + _current, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (_current !== null) { + // An incomplete component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + // Promote the fiber to a class and try rendering again. + workInProgress.tag = ClassComponent; + + // The rest of this function is a fork of `updateClassComponent` + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); +} + +function mountIndeterminateComponent( + _current, + workInProgress, + Component, + renderExpirationTime +) { + if (_current !== null) { + // An indeterminate component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); + var context = getMaskedContext(workInProgress, unmaskedContext); + + prepareToReadContext(workInProgress, renderExpirationTime); + + var value = void 0; + + { + if ( + Component.prototype && + typeof Component.prototype.render === "function" + ) { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutBadClass[componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + + "This is likely to cause errors. Change %s to extend React.Component instead.", + componentName, + componentName + ); + didWarnAboutBadClass[componentName] = true; + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } + + ReactCurrentOwner$3.current = workInProgress; + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + { + var _componentName = getComponentName(Component) || "Unknown"; + if (!didWarnAboutModulePatternComponent[_componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to be a function component that returns a class instance. " + + "Change %s to a class that extends React.Component instead. " + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + + "cannot be called with `new` by React.", + _componentName, + _componentName, + _componentName + ); + didWarnAboutModulePatternComponent[_componentName] = true; + } + } + + // Proceed under the assumption that this is a class instance + workInProgress.tag = ClassComponent; + + // Throw out any hooks that were used. + resetHooks(); + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = false; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + workInProgress.memoizedState = + value.state !== null && value.state !== undefined ? value.state : null; + + var getDerivedStateFromProps = Component.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + props + ); + } + + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, Component, props, renderExpirationTime); + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); + } else { + // Proceed under the assumption that this is a function component + workInProgress.tag = FunctionComponent; + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + } + } + reconcileChildren(null, workInProgress, value, renderExpirationTime); + { + validateFunctionComponentInDev(workInProgress, Component); + } + return workInProgress.child; + } +} + +function validateFunctionComponentInDev(workInProgress, Component) { + if (Component) { + !!Component.childContextTypes + ? warningWithoutStack$1( + false, + "%s(...): childContextTypes cannot be defined on a function component.", + Component.displayName || Component.name || "Component" + ) + : void 0; + } + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + + var warningKey = ownerName || workInProgress._debugID || ""; + var debugSource = workInProgress._debugSource; + if (debugSource) { + warningKey = debugSource.fileName + ":" + debugSource.lineNumber; + } + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; + warning$1( + false, + "Function components cannot be given refs. " + + "Attempts to access this ref will fail. " + + "Did you mean to use React.forwardRef()?%s", + info + ); + } + } + + if (typeof Component.getDerivedStateFromProps === "function") { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) { + warningWithoutStack$1( + false, + "%s: Function components do not support getDerivedStateFromProps.", + componentName + ); + didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true; + } + } + + if ( + typeof Component.contextType === "object" && + Component.contextType !== null + ) { + var _componentName2 = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName2]) { + warningWithoutStack$1( + false, + "%s: Function components do not support contextType.", + _componentName2 + ); + didWarnAboutContextTypeOnFunctionComponent[_componentName2] = true; + } + } +} + +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode; + var nextProps = workInProgress.pendingProps; + + { + if (shouldSuspend(workInProgress)) { + workInProgress.effectTag |= DidCapture; + } + } + + // We should attempt to render the primary children unless this boundary + // already suspended during this render (`alreadyCaptured` is true). + var nextState = workInProgress.memoizedState; + + var nextDidTimeout = void 0; + if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This is the first attempt. + nextState = null; + nextDidTimeout = false; + } else { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + nextState = { + fallbackExpirationTime: + nextState !== null ? nextState.fallbackExpirationTime : NoWork + }; + nextDidTimeout = true; + workInProgress.effectTag &= ~DidCapture; + } + + { + if ("maxDuration" in nextProps) { + if (!didWarnAboutMaxDuration) { + didWarnAboutMaxDuration = true; + warning$1( + false, + "maxDuration has been removed from React. " + + "Remove the maxDuration prop." + ); + } + } + } + + // This next part is a bit confusing. If the children timeout, we switch to + // showing the fallback children in place of the "primary" children. + // However, we don't want to delete the primary children because then their + // state will be lost (both the React state and the host state, e.g. + // uncontrolled form inputs). Instead we keep them mounted and hide them. + // Both the fallback children AND the primary children are rendered at the + // same time. Once the primary children are un-suspended, we can delete + // the fallback children — don't need to preserve their state. + // + // The two sets of children are siblings in the host environment, but + // semantically, for purposes of reconciliation, they are two separate sets. + // So we store them using two fragment fibers. + // + // However, we want to avoid allocating extra fibers for every placeholder. + // They're only necessary when the children time out, because that's the + // only time when both sets are mounted. + // + // So, the extra fragment fibers are only used if the children time out. + // Otherwise, we render the primary children directly. This requires some + // custom reconciliation logic to preserve the state of the primary + // children. It's essentially a very basic form of re-parenting. + + // `child` points to the child fiber. In the normal case, this is the first + // fiber of the primary children set. In the timed-out case, it's a + // a fragment fiber containing the primary children. + var child = void 0; + // `next` points to the next fiber React should render. In the normal case, + // it's the same as `child`: the first fiber of the primary children set. + // In the timed-out case, it's a fragment fiber containing the *fallback* + // children -- we skip over the primary children entirely. + var next = void 0; + if (current$$1 === null) { + if (enableSuspenseServerRenderer) { + // If we're currently hydrating, try to hydrate this boundary. + // But only if this has a fallback. + if (nextProps.fallback !== undefined) { + tryToClaimNextHydratableInstance(workInProgress); + // This could've changed the tag if this was a dehydrated suspense component. + if (workInProgress.tag === DehydratedSuspenseComponent) { + return updateDehydratedSuspenseComponent( + null, + workInProgress, + renderExpirationTime + ); + } + } + } + + // This is the initial mount. This branch is pretty simple because there's + // no previous state that needs to be preserved. + if (nextDidTimeout) { + // Mount separate fragments for primary and fallback children. + var nextFallbackChildren = nextProps.fallback; + var primaryChildFragment = createFiberFromFragment( + null, + mode, + NoWork, + null + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var progressedState = workInProgress.memoizedState; + var progressedPrimaryChild = + progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + primaryChildFragment.child = progressedPrimaryChild; + } + + var fallbackChildFragment = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + primaryChildFragment.sibling = fallbackChildFragment; + child = primaryChildFragment; + // Skip the primary children, and continue working on the + // fallback children. + next = fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // Mount the primary children without an intermediate fragment fiber. + var nextPrimaryChildren = nextProps.children; + child = next = mountChildFibers( + workInProgress, + null, + nextPrimaryChildren, + renderExpirationTime + ); + } + } else { + // This is an update. This branch is more complicated because we need to + // ensure the state of the primary children is preserved. + var prevState = current$$1.memoizedState; + var prevDidTimeout = prevState !== null; + if (prevDidTimeout) { + // The current tree already timed out. That means each child set is + var currentPrimaryChildFragment = current$$1.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + if (nextDidTimeout) { + // Still timed out. Reuse the current primary children by cloning + // its fragment. We're going to skip over these entirely. + var _nextFallbackChildren = nextProps.fallback; + var _primaryChildFragment = createWorkInProgress( + currentPrimaryChildFragment, + currentPrimaryChildFragment.pendingProps, + NoWork + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState = workInProgress.memoizedState; + var _progressedPrimaryChild = + _progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { + _primaryChildFragment.child = _progressedPrimaryChild; + } + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var treeBaseDuration = 0; + var hiddenChild = _primaryChildFragment.child; + while (hiddenChild !== null) { + treeBaseDuration += hiddenChild.treeBaseDuration; + hiddenChild = hiddenChild.sibling; + } + _primaryChildFragment.treeBaseDuration = treeBaseDuration; + } + + // Clone the fallback child fragment, too. These we'll continue + // working on. + var _fallbackChildFragment = (_primaryChildFragment.sibling = createWorkInProgress( + currentFallbackChildFragment, + _nextFallbackChildren, + currentFallbackChildFragment.expirationTime + )); + child = _primaryChildFragment; + _primaryChildFragment.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // No longer suspended. Switch back to showing the primary children, + // and remove the intermediate fragment fiber. + var _nextPrimaryChildren = nextProps.children; + var currentPrimaryChild = currentPrimaryChildFragment.child; + var primaryChild = reconcileChildFibers( + workInProgress, + currentPrimaryChild, + _nextPrimaryChildren, + renderExpirationTime + ); + + // If this render doesn't suspend, we need to delete the fallback + // children. Wait until the complete phase, after we've confirmed the + // fallback is no longer needed. + // TODO: Would it be better to store the fallback fragment on + // the stateNode? + + // Continue rendering the children, like we normally do. + child = next = primaryChild; + } + } else { + // The current tree has not already timed out. That means the primary + // children are not wrapped in a fragment fiber. + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + // Timed out. Wrap the children in a fragment fiber to keep them + // separate from the fallback children. + var _nextFallbackChildren2 = nextProps.fallback; + var _primaryChildFragment2 = createFiberFromFragment( + // It shouldn't matter what the pending props are because we aren't + // going to render this fragment. + null, + mode, + NoWork, + null + ); + _primaryChildFragment2.child = _currentPrimaryChild; + + // Even though we're creating a new fiber, there are no new children, + // because we're reusing an already mounted tree. So we don't need to + // schedule a placement. + // primaryChildFragment.effectTag |= Placement; + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState2 = workInProgress.memoizedState; + var _progressedPrimaryChild2 = + _progressedState2 !== null + ? workInProgress.child.child + : workInProgress.child; + _primaryChildFragment2.child = _progressedPrimaryChild2; + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var _treeBaseDuration = 0; + var _hiddenChild = _primaryChildFragment2.child; + while (_hiddenChild !== null) { + _treeBaseDuration += _hiddenChild.treeBaseDuration; + _hiddenChild = _hiddenChild.sibling; + } + _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; + } + + // Create a fragment from the fallback children, too. + var _fallbackChildFragment2 = (_primaryChildFragment2.sibling = createFiberFromFragment( + _nextFallbackChildren2, + mode, + renderExpirationTime, + null + )); + _fallbackChildFragment2.effectTag |= Placement; + child = _primaryChildFragment2; + _primaryChildFragment2.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment2; + child.return = next.return = workInProgress; + } else { + // Still haven't timed out. Continue rendering the children, like we + // normally do. + var _nextPrimaryChildren2 = nextProps.children; + next = child = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + _nextPrimaryChildren2, + renderExpirationTime + ); + } + } + workInProgress.stateNode = current$$1.stateNode; + } + + workInProgress.memoizedState = nextState; + workInProgress.child = child; + return next; +} + +function retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime +) { + // Detach from the current dehydrated boundary. + current$$1.alternate = null; + workInProgress.alternate = null; + + // Insert a deletion in the effect list. + var returnFiber = workInProgress.return; + (function() { + if (!(returnFiber !== null)) { + throw ReactError( + "Suspense boundaries are never on the root. This is probably a bug in React." + ); + } + })(); + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = current$$1; + returnFiber.lastEffect = current$$1; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = current$$1; + } + current$$1.nextEffect = null; + current$$1.effectTag = Deletion; + + // Upgrade this work in progress to a real Suspense component. + workInProgress.tag = SuspenseComponent; + workInProgress.stateNode = null; + workInProgress.memoizedState = null; + // This is now an insertion. + workInProgress.effectTag |= Placement; + // Retry as a real Suspense component. + return updateSuspenseComponent(null, workInProgress, renderExpirationTime); +} + +function updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var suspenseInstance = workInProgress.stateNode; + if (current$$1 === null) { + // During the first pass, we'll bail out and not drill into the children. + // Instead, we'll leave the content in place and try to hydrate it later. + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This is a client-only boundary. Since we won't get any content from the server + // for this, we need to schedule that at a higher priority based on when it would + // have timed out. In theory we could render it in this pass but it would have the + // wrong priority associated with it and will prevent hydration of parent path. + // Instead, we'll leave work left on it to render it in a separate commit. + + // TODO This time should be the time at which the server rendered response that is + // a parent to this boundary was displayed. However, since we currently don't have + // a protocol to transfer that time, we'll just estimate it by using the current + // time. This will mean that Suspense timeouts are slightly shifted to later than + // they should be. + var serverDisplayTime = requestCurrentTime(); + // Schedule a normal pri update to render this content. + workInProgress.expirationTime = computeAsyncExpiration(serverDisplayTime); + } else { + // We'll continue hydrating the rest at offscreen priority since we'll already + // be showing the right content coming from the server, it is no rush. + workInProgress.expirationTime = Never; + } + return null; + } + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Leave the existing children in place. + // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? + workInProgress.child = null; + return null; + } + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This boundary is in a permanent fallback state. In this case, we'll never + // get an update and we'll never be able to hydrate the final content. Let's just try the + // client side render instead. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } + // We use childExpirationTime to indicate that a child might depend on context, so if + // any context has changed, we need to treat is as if the input might have changed. + var hasContextChanged$$1 = + current$$1.childExpirationTime >= renderExpirationTime; + if (didReceiveUpdate || hasContextChanged$$1) { + // This boundary has changed since the first render. This means that we are now unable to + // hydrate it. We might still be able to hydrate it using an earlier expiration time but + // during this render we can't. Instead, we're going to delete the whole subtree and + // instead inject a new real Suspense boundary to take its place, which may render content + // or fallback. The real Suspense boundary will suspend for a while so we have some time + // to ensure it can produce real content, but all state and pending events will be lost. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } else if (isSuspenseInstancePending(suspenseInstance)) { + // This component is still pending more data from the server, so we can't hydrate its + // content. We treat it as if this component suspended itself. It might seem as if + // we could just try to render it client-side instead. However, this will perform a + // lot of unnecessary work and is unlikely to complete since it often will suspend + // on missing data anyway. Additionally, the server might be able to render more + // than we can on the client yet. In that case we'd end up with more fallback states + // on the client than if we just leave it alone. If the server times out or errors + // these should update this boundary to the permanent Fallback state instead. + // Mark it as having captured (i.e. suspended). + workInProgress.effectTag |= DidCapture; + // Leave the children in place. I.e. empty. + workInProgress.child = null; + // Register a callback to retry this boundary once the server has sent the result. + registerSuspenseInstanceRetry( + suspenseInstance, + retryTimedOutBoundary.bind(null, current$$1) + ); + return null; + } else { + // This is the first attempt. + reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; + } +} + +function updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + if (current$$1 === null) { + // Portals are special because we don't append the children during mount + // but at commit. Therefore we need to track insertions which the normal + // flow doesn't do during mount. This doesn't happen at the root because + // the root always starts with a "current" with a null child. + // TODO: Consider unifying this with how the root works. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + return workInProgress.child; +} + +function updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime +) { + var providerType = workInProgress.type; + var context = providerType._context; + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = newProps.value; + + { + var providerPropTypes = workInProgress.type.propTypes; + + if (providerPropTypes) { + checkPropTypes( + providerPropTypes, + newProps, + "prop", + "Context.Provider", + getCurrentFiberStackInDev + ); + } + } + + pushProvider(workInProgress, newValue); + + if (oldProps !== null) { + var oldValue = oldProps.value; + var changedBits = calculateChangedBits(context, newValue, oldValue); + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children && !hasContextChanged()) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } + } + + var newChildren = newProps.children; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +var hasWarnedAboutUsingContextAsConsumer = false; + +function updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime +) { + var context = workInProgress.type; + // The logic below for Context differs depending on PROD or DEV mode. In + // DEV mode, we create a separate object for Context.Consumer that acts + // like a proxy to Context. This proxy object adds unnecessary code in PROD + // so we use the old behaviour (Context.Consumer references Context) to + // reduce size and overhead. The separate object references context via + // a property called "_context", which also gives us the ability to check + // in DEV mode if this property exists or not and warn if it does not. + { + if (context._context === undefined) { + // This may be because it's a Context (rather than a Consumer). + // Or it may be because it's older React where they're the same thing. + // We only want to warn if we're sure it's a new React. + if (context !== context.Consumer) { + if (!hasWarnedAboutUsingContextAsConsumer) { + hasWarnedAboutUsingContextAsConsumer = true; + warning$1( + false, + "Rendering directly is not supported and will be removed in " + + "a future major release. Did you mean to render instead?" + ); + } + } + } else { + context = context._context; + } + } + var newProps = workInProgress.pendingProps; + var render = newProps.children; + + { + !(typeof render === "function") + ? warningWithoutStack$1( + false, + "A context consumer was rendered with multiple children, or a child " + + "that isn't a function. A context consumer expects a single child " + + "that is a function. If you did pass a function, make sure there " + + "is no trailing or leading whitespace around it." + ) + : void 0; + } + + prepareToReadContext(workInProgress, renderExpirationTime); + var newValue = readContext(context, newProps.unstable_observedBits); + var newChildren = void 0; + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + newChildren = render(newValue); + setCurrentPhase(null); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime +) { + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + pushHostContextForEventComponent(workInProgress); + return workInProgress.child; +} + +function updateEventTarget(current$$1, workInProgress, renderExpirationTime) { + var type = workInProgress.type.type; + var nextProps = workInProgress.pendingProps; + var eventTargetChild = getEventTargetChildElement(type, nextProps); + + { + !(nextProps.children == null) + ? warning$1(false, "Event targets should not have children.") + : void 0; + } + if (eventTargetChild !== null) { + var child = (workInProgress.child = createFiberFromTypeAndProps( + eventTargetChild.type, + null, + eventTargetChild.props, + null, + workInProgress.mode, + renderExpirationTime + )); + child.return = workInProgress; + + if (current$$1 === null || current$$1.child === null) { + child.effectTag = Placement; + } + } else { + reconcileChildren(current$$1, workInProgress, null, renderExpirationTime); + } + pushHostContextForEventTarget(workInProgress); + return workInProgress.child; +} + +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} + +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + cancelWorkTimer(workInProgress); + + if (current$$1 !== null) { + // Reuse previous context list + workInProgress.contextDependencies = current$$1.contextDependencies; + } + + if (enableProfilerTimer) { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(workInProgress); + } + + // Check if the children have any pending work. + var childExpirationTime = workInProgress.childExpirationTime; + if (childExpirationTime < renderExpirationTime) { + // The children don't have any work either. We can skip them. + // TODO: Once we add back resuming, we should check if the children are + // a work-in-progress set. If so, we need to transfer their effects. + return null; + } else { + // This fiber doesn't have work, but its subtree does. Clone the child + // fibers and continue. + cloneChildFibers(current$$1, workInProgress); + return workInProgress.child; + } +} + +function beginWork$1(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + + if (current$$1 !== null) { + var oldProps = current$$1.memoizedProps; + var newProps = workInProgress.pendingProps; + + if (oldProps !== newProps || hasContextChanged()) { + // If props or context changed, mark the fiber as having performed work. + // This may be unset if the props are determined to be equal later (memo). + didReceiveUpdate = true; + } else if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = false; + // This fiber does not have any pending work. Bailout without entering + // the begin phase. There's still some bookkeeping we that needs to be done + // in this optimized path, mostly pushing stuff onto the stack. + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + resetHydrationState(); + break; + case HostComponent: + pushHostContext(workInProgress); + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); + } + break; + } + case HostPortal: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case ContextProvider: { + var newValue = workInProgress.memoizedProps.value; + pushProvider(workInProgress, newValue); + break; + } + case Profiler: + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + break; + case SuspenseComponent: { + var state = workInProgress.memoizedState; + var didTimeout = state !== null; + if (didTimeout) { + // If this boundary is currently timed out, we need to decide + // whether to retry the primary children, or to skip over it and + // go straight to the fallback. Check the priority of the primary + var primaryChildFragment = workInProgress.child; + var primaryChildExpirationTime = + primaryChildFragment.childExpirationTime; + if ( + primaryChildExpirationTime !== NoWork && + primaryChildExpirationTime >= renderExpirationTime + ) { + // The primary children have pending work. Use the normal path + // to attempt to render the primary children again. + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } else { + // The primary children do not have pending work with sufficient + // priority. Bailout. + var child = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; + } else { + return null; + } + } + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // We know that this component will suspend again because if it has + // been unsuspended it has committed as a regular Suspense component. + // If it needs to be retried, it should have work scheduled on it. + workInProgress.effectTag |= DidCapture; + } + break; + } + case EventComponent: + if (enableEventAPI) { + pushHostContextForEventComponent(workInProgress); + } + break; + case EventTarget: { + if (enableEventAPI) { + pushHostContextForEventTarget(workInProgress); + } + break; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + didReceiveUpdate = false; + } + + // Before entering the begin phase, clear the expiration time. + workInProgress.expirationTime = NoWork; + + switch (workInProgress.tag) { + case IndeterminateComponent: { + var elementType = workInProgress.elementType; + return mountIndeterminateComponent( + current$$1, + workInProgress, + elementType, + renderExpirationTime + ); + } + case LazyComponent: { + var _elementType = workInProgress.elementType; + return mountLazyComponent( + current$$1, + workInProgress, + _elementType, + updateExpirationTime, + renderExpirationTime + ); + } + case FunctionComponent: { + var _Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = + workInProgress.elementType === _Component + ? unresolvedProps + : resolveDefaultProps(_Component, unresolvedProps); + return updateFunctionComponent( + current$$1, + workInProgress, + _Component, + resolvedProps, + renderExpirationTime + ); + } + case ClassComponent: { + var _Component2 = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; + var _resolvedProps = + workInProgress.elementType === _Component2 + ? _unresolvedProps + : resolveDefaultProps(_Component2, _unresolvedProps); + return updateClassComponent( + current$$1, + workInProgress, + _Component2, + _resolvedProps, + renderExpirationTime + ); + } + case HostRoot: + return updateHostRoot(current$$1, workInProgress, renderExpirationTime); + case HostComponent: + return updateHostComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostText: + return updateHostText(current$$1, workInProgress); + case SuspenseComponent: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostPortal: + return updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case ForwardRef: { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; + var _resolvedProps2 = + workInProgress.elementType === type + ? _unresolvedProps2 + : resolveDefaultProps(type, _unresolvedProps2); + return updateForwardRef( + current$$1, + workInProgress, + type, + _resolvedProps2, + renderExpirationTime + ); + } + case Fragment: + return updateFragment(current$$1, workInProgress, renderExpirationTime); + case Mode: + return updateMode(current$$1, workInProgress, renderExpirationTime); + case Profiler: + return updateProfiler(current$$1, workInProgress, renderExpirationTime); + case ContextProvider: + return updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime + ); + case ContextConsumer: + return updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime + ); + case MemoComponent: { + var _type2 = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; + // Resolve outer props first, then resolve inner props. + var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = _type2.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + _resolvedProps3, // Resolved for outer only + "prop", + getComponentName(_type2), + getCurrentFiberStackInDev + ); + } + } + } + _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); + return updateMemoComponent( + current$$1, + workInProgress, + _type2, + _resolvedProps3, + updateExpirationTime, + renderExpirationTime + ); + } + case SimpleMemoComponent: { + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + } + case IncompleteClassComponent: { + var _Component3 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; + var _resolvedProps4 = + workInProgress.elementType === _Component3 + ? _unresolvedProps4 + : resolveDefaultProps(_Component3, _unresolvedProps4); + return mountIncompleteClassComponent( + current$$1, + workInProgress, + _Component3, + _resolvedProps4, + renderExpirationTime + ); + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + return updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventComponent: { + if (enableEventAPI) { + return updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventTarget: { + if (enableEventAPI) { + return updateEventTarget( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + } + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.effectTag |= Update; +} + +function markRef$1(workInProgress) { + workInProgress.effectTag |= Ref; +} + +var appendAllChildren = void 0; +var updateHostContainer = void 0; +var updateHostComponent$1 = void 0; +var updateHostText$1 = void 0; +if (supportsMutation) { + // Mutation mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + if (node.tag === HostComponent || node.tag === HostText) { + appendInitialChild(parent, node.stateNode); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // If we have an alternate, that means this is an update and we need to + // schedule a side-effect to do the updates. + var oldProps = current.memoizedProps; + if (oldProps === newProps) { + // In mutation mode, this is sufficient for a bailout because + // we won't touch this node even if children changed. + return; + } + + // If we get updated because one of our children updated, we don't + // have newProps so we'll have to reuse them. + // TODO: Split the update API as separate for the props vs. children. + // Even better would be if children weren't special cased at all tho. + var instance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + // TODO: Experiencing an error where oldProps is null. Suggests a host + // component is hitting the resume path. Figure out why. Possibly + // related to `hidden`. + var updatePayload = prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + // TODO: Type this specific to this type of component. + workInProgress.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. All the work is done in commitWork. + if (updatePayload) { + markUpdate(workInProgress); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); + } + }; +} else if (supportsPersistence) { + // Persistent host tree mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendInitialChild(parent, instance); + } else if (node.tag === HostText) { + var _instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance = cloneHiddenTextInstance(_instance, text, node); + } + appendInitialChild(parent, _instance); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildren( + parent, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + // An unfortunate fork of appendAllChildren because we have two different parent types. + var appendAllChildrenToContainer = function( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendChildToContainerChildSet(containerChildSet, instance); + } else if (node.tag === HostText) { + var _instance2 = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance2 = cloneHiddenTextInstance(_instance2, text, node); + } + appendChildToContainerChildSet(containerChildSet, _instance2); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged) { + // No changes, just reuse the existing instance. + } else { + var container = portalOrRoot.containerInfo; + var newChildSet = createContainerChildSet(container); + // If children might have changed, we have to add them all to the set. + appendAllChildrenToContainer(newChildSet, workInProgress, false, false); + portalOrRoot.pendingChildren = newChildSet; + // Schedule an update on the container to swap out the container. + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + var currentInstance = current.stateNode; + var oldProps = current.memoizedProps; + // If there are no effects associated with this node, then none of our children had any updates. + // This guarantees that we can reuse all of them. + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged && oldProps === newProps) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var recyclableInstance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + var updatePayload = null; + if (oldProps !== newProps) { + updatePayload = prepareUpdate( + recyclableInstance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + } + if (childrenUnchanged && updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var newInstance = cloneInstance( + currentInstance, + updatePayload, + type, + oldProps, + newProps, + workInProgress, + childrenUnchanged, + recyclableInstance + ); + if ( + finalizeInitialChildren( + newInstance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = newInstance; + if (childrenUnchanged) { + // If there are no other effects in this tree, we need to flag this node as having one. + // Even though we're not going to use it for anything. + // Otherwise parents won't know that there are new children to propagate upwards. + markUpdate(workInProgress); + } else { + // If children might have changed, we have to add them all to the set. + appendAllChildren(newInstance, workInProgress, false, false); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + if (oldText !== newText) { + // If the text content differs, we'll create a new text instance for it. + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + workInProgress.stateNode = createTextInstance( + newText, + rootContainerInstance, + currentHostContext, + workInProgress + ); + // We'll have to mark it as having an effect, even though we won't use the effect for anything. + // This lets the parents know that at least one of their children has changed. + markUpdate(workInProgress); + } + }; +} else { + // No host operations + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // Noop + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // Noop + }; +} + +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + + switch (workInProgress.tag) { + case IndeterminateComponent: + break; + case LazyComponent: + break; + case SimpleMemoComponent: + case FunctionComponent: + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + break; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var fiberRoot = workInProgress.stateNode; + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } + if (current === null || current.child === null) { + // If we hydrated, pop so that we can delete any remaining children + // that weren't hydrated. + popHydrationState(workInProgress); + // This resets the hacky state to fix isMounted before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag &= ~Placement; + } + updateHostContainer(workInProgress); + break; + } + case HostComponent: { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ); + + if (current.ref !== workInProgress.ref) { + markRef$1(workInProgress); + } + } else { + if (!newProps) { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + break; + } + + var currentHostContext = getHostContext(); + // TODO: Move createInstance to beginWork and keep it on a context + // "stack" as the parent. Then append children as we go in beginWork + // or completeWork depending on we want to add then top->down or + // bottom->up. Top->down is faster in IE11. + var wasHydrated = popHydrationState(workInProgress); + if (wasHydrated) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + if ( + prepareToHydrateHostInstance( + workInProgress, + rootContainerInstance, + currentHostContext + ) + ) { + // If changes to the hydrated node needs to be applied at the + // commit-phase we mark this as such. + markUpdate(workInProgress); + } + } else { + var instance = createInstance( + type, + newProps, + rootContainerInstance, + currentHostContext, + workInProgress + ); + + appendAllChildren(instance, workInProgress, false, false); + + // Certain renderers require commit-time effects for initial mount. + // (eg DOM renderer supports auto-focus for certain elements). + // Make sure such renderers get scheduled for later work. + if ( + finalizeInitialChildren( + instance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = instance; + } + + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef$1(workInProgress); + } + } + break; + } + case HostText: { + var newText = newProps; + if (current && workInProgress.stateNode != null) { + var oldText = current.memoizedProps; + // If we have an alternate, that means this is an update and we need + // to schedule a side-effect to do the updates. + updateHostText$1(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + } + var _rootContainerInstance = getRootHostContainer(); + var _currentHostContext = getHostContext(); + var _wasHydrated = popHydrationState(workInProgress); + if (_wasHydrated) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance, + _currentHostContext, + workInProgress + ); + } + } + break; + } + case ForwardRef: + break; + case SuspenseComponent: { + var nextState = workInProgress.memoizedState; + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Re-render with the fallback children. + workInProgress.expirationTime = renderExpirationTime; + // Do not reset the effect list. + return workInProgress; + } + + var nextDidTimeout = nextState !== null; + var prevDidTimeout = false; + if (current === null) { + // In cases where we didn't find a suitable hydration boundary we never + // downgraded this to a DehydratedSuspenseComponent, but we still need to + // pop the hydration state since we might be inside the insertion tree. + popHydrationState(workInProgress); + } else { + var prevState = current.memoizedState; + prevDidTimeout = prevState !== null; + if (!nextDidTimeout && prevState !== null) { + // We just switched from the fallback to the normal children. + + // Mark the event time of the switching from fallback to normal children, + // based on the start of when we first showed the fallback. This time + var fallbackExpirationTime = prevState.fallbackExpirationTime; + markRenderEventTime(fallbackExpirationTime); + + // Delete the fallback. + // TODO: Would it be better to store the fallback fragment on + // the stateNode during the begin phase? + var currentFallbackChild = current.child.sibling; + if (currentFallbackChild !== null) { + // Deletions go at the beginning of the return fiber's effect list + var first = workInProgress.firstEffect; + if (first !== null) { + workInProgress.firstEffect = currentFallbackChild; + currentFallbackChild.nextEffect = first; + } else { + workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; + currentFallbackChild.nextEffect = null; + } + currentFallbackChild.effectTag = Deletion; + } + } + } + + if (nextDidTimeout && !prevDidTimeout) { + // If this subtreee is running in concurrent mode we can suspend, + // otherwise we won't suspend. + // TODO: This will still suspend a synchronous tree if anything + // in the concurrent tree already suspended during this render. + // This is a known bug. + if ((workInProgress.mode & ConcurrentMode) !== NoContext) { + renderDidSuspend(); + } + } + + if (supportsPersistence) { + // TODO: Only schedule updates if not prevDidTimeout. + if (nextDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. + workInProgress.effectTag |= Update; + } + } + if (supportsMutation) { + // TODO: Only schedule updates if these values are non equal, i.e. it changed. + if (nextDidTimeout || prevDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. In mutation mode, we also need the flag to + // *unhide* children that were previously hidden, so check if the + // is currently timed out, too. + workInProgress.effectTag |= Update; + } + } + break; + } + case Fragment: + break; + case Mode: + break; + case Profiler: + break; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case ContextProvider: + // Pop provider fiber + popProvider(workInProgress); + break; + case ContextConsumer: + break; + case MemoComponent: + break; + case IncompleteClassComponent: { + // Same as class component case. I put it down here so that the tags are + // sequential to ensure this switch is compiled to a jump table. + var _Component = workInProgress.type; + if (isContextProvider(_Component)) { + popContext(workInProgress); + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + if (current === null) { + var _wasHydrated2 = popHydrationState(workInProgress); + (function() { + if (!_wasHydrated2) { + throw ReactError( + "A dehydrated suspense component was completed without a hydrated node. This is probably a bug in React." + ); + } + })(); + skipPastDehydratedSuspenseInstance(workInProgress); + } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This boundary did not suspend so it's now hydrated. + // To handle any future suspense cases, we're going to now upgrade it + // to a Suspense component. We detach it from the existing current fiber. + current.alternate = null; + workInProgress.alternate = null; + workInProgress.tag = SuspenseComponent; + workInProgress.memoizedState = null; + workInProgress.stateNode = null; + } + } + break; + } + case EventComponent: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _rootContainerInstance2 = getRootHostContainer(); + var responder = workInProgress.type.responder; + var eventComponentInstance = workInProgress.stateNode; + + if (eventComponentInstance === null) { + var responderState = null; + if (responder.createInitialState !== undefined) { + responderState = responder.createInitialState(newProps); + } + eventComponentInstance = workInProgress.stateNode = { + currentFiber: workInProgress, + props: newProps, + responder: responder, + rootEventTypes: null, + rootInstance: _rootContainerInstance2, + state: responderState + }; + markUpdate(workInProgress); + } else { + // Update the props on the event component state node + eventComponentInstance.props = newProps; + // Update the root container, so we can properly unmount events at some point + eventComponentInstance.rootInstance = _rootContainerInstance2; + // Update the current fiber + eventComponentInstance.currentFiber = workInProgress; + updateEventComponent(eventComponentInstance); + } + } + break; + } + case EventTarget: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _type = workInProgress.type.type; + var _rootContainerInstance3 = getRootHostContainer(); + var shouldUpdate = handleEventTarget( + _type, + newProps, + _rootContainerInstance3, + workInProgress + ); + // Update the latest props on the stateNode. This is used + // during the event phase to find the most current props. + workInProgress.stateNode.props = newProps; + if (shouldUpdate) { + markUpdate(workInProgress); + } + } + break; + } + default: + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + return null; +} + +function shouldCaptureSuspense(workInProgress) { + // In order to capture, the Suspense component must have a fallback prop. + if (workInProgress.memoizedProps.fallback === undefined) { + return false; + } + // If it was the primary children that just suspended, capture and render the + // fallback. Otherwise, don't capture and bubble to the next boundary. + var nextState = workInProgress.memoizedState; + return nextState === null; +} + +function createCapturedValue(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} + +// Module provided by RN: +/** + * Intercept lifecycle errors and ensure they are shown with the correct stack + * trace within the native redbox component. + */ +function showErrorDialog(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + + var errorToHandle = void 0; + + // Typically Errors are thrown but eg strings or null can be thrown as well. + if (error instanceof Error) { + var message = error.message, + name = error.name; + + var summary = message ? name + ": " + message : name; + + errorToHandle = error; + + try { + errorToHandle.message = + summary + "\n\nThis error is located at:" + componentStack; + } catch (e) {} + } else if (typeof error === "string") { + errorToHandle = new Error( + error + "\n\nThis error is located at:" + componentStack + ); + } else { + errorToHandle = new Error("Unspecified error at:" + componentStack); + } + + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); + + // Return false here to prevent ReactFiberErrorLogger default behavior of + // logging error details to console.error. Calls to console.error are + // automatically routed to the native redbox controller, which we've already + // done above by calling ExceptionsManager. + return false; +} + +function logCapturedError(capturedError) { + var logError = showErrorDialog(capturedError); + + // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + if (logError === false) { + return; + } + + var error = capturedError.error; + { + var componentName = capturedError.componentName, + componentStack = capturedError.componentStack, + errorBoundaryName = capturedError.errorBoundaryName, + errorBoundaryFound = capturedError.errorBoundaryFound, + willRetry = capturedError.willRetry; + + // Browsers support silencing uncaught errors by calling + // `preventDefault()` in window `error` handler. + // We record this information as an expando on the error. + + if (error != null && error._suppressLogging) { + if (errorBoundaryFound && willRetry) { + // The error is recoverable and was silenced. + // Ignore it and don't print the stack addendum. + // This is handy for testing error boundaries without noise. + return; + } + // The error is fatal. Since the silencing might have + // been accidental, we'll surface it anyway. + // However, the browser would have silenced the original error + // so we'll print it first, and then print the stack addendum. + console.error(error); + // For a more detailed description of this block, see: + // https://github.com/facebook/react/pull/13384 + } + + var componentNameMessage = componentName + ? "The above error occurred in the <" + componentName + "> component:" + : "The above error occurred in one of your React components:"; + + var errorBoundaryMessage = void 0; + // errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow. + if (errorBoundaryFound && errorBoundaryName) { + if (willRetry) { + errorBoundaryMessage = + "React will try to recreate this component tree from scratch " + + ("using the error boundary you provided, " + errorBoundaryName + "."); + } else { + errorBoundaryMessage = + "This error was initially handled by the error boundary " + + errorBoundaryName + + ".\n" + + "Recreating the tree from scratch failed so React will unmount the tree."; + } + } else { + errorBoundaryMessage = + "Consider adding an error boundary to your tree to customize error handling behavior.\n" + + "Visit https://fb.me/react-error-boundaries to learn more about error boundaries."; + } + var combinedMessage = + "" + + componentNameMessage + + componentStack + + "\n\n" + + ("" + errorBoundaryMessage); + + // In development, we provide our own message with just the component stack. + // We don't include the original error message and JS stack because the browser + // has already printed it. Even if the application swallows the error, it is still + // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. + console.error(combinedMessage); + } +} + +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + +var PossiblyWeakSet$1 = typeof WeakSet === "function" ? WeakSet : Set; + +function logError(boundary, errorInfo) { + var source = errorInfo.source; + var stack = errorInfo.stack; + if (stack === null && source !== null) { + stack = getStackByFiberInDevAndProd(source); + } + + var capturedError = { + componentName: source !== null ? getComponentName(source.type) : null, + componentStack: stack !== null ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: false, + willRetry: false + }; + + if (boundary !== null && boundary.tag === ClassComponent) { + capturedError.errorBoundary = boundary.stateNode; + capturedError.errorBoundaryName = getComponentName(boundary.type); + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; + } + + try { + logCapturedError(capturedError); + } catch (e) { + // This method must not throw, or React internal state will get messed up. + // If console.error is overridden, or logCapturedError() shows a dialog that throws, + // we want to report this error outside of the normal stack as a last resort. + // https://github.com/facebook/react/issues/13188 + setTimeout(function() { + throw e; + }); + } +} + +var callComponentWillUnmountWithTimer = function(current$$1, instance) { + startPhaseTimer(current$$1, "componentWillUnmount"); + instance.props = current$$1.memoizedProps; + instance.state = current$$1.memoizedState; + instance.componentWillUnmount(); + stopPhaseTimer(); +}; + +// Capture errors so they don't interrupt unmounting. +function safelyCallComponentWillUnmount(current$$1, instance) { + { + invokeGuardedCallback( + null, + callComponentWillUnmountWithTimer, + null, + current$$1, + instance + ); + if (hasCaughtError()) { + var unmountError = clearCaughtError(); + captureCommitPhaseError(current$$1, unmountError); + } + } +} + +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (ref !== null) { + if (typeof ref === "function") { + { + invokeGuardedCallback(null, ref, null, null); + if (hasCaughtError()) { + var refError = clearCaughtError(); + captureCommitPhaseError(current$$1, refError); + } + } + } else { + ref.current = null; + } + } +} + +function safelyCallDestroy(current$$1, destroy) { + { + invokeGuardedCallback(null, destroy, null); + if (hasCaughtError()) { + var error = clearCaughtError(); + captureCommitPhaseError(current$$1, error); + } + } +} + +function commitBeforeMutationLifeCycles(current$$1, finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); + return; + } + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var instance = finishedWork.stateNode; + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + var snapshot = instance.getSnapshotBeforeUpdate( + finishedWork.elementType === finishedWork.type + ? prevProps + : resolveDefaultProps(finishedWork.type, prevProps), + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); + warningWithoutStack$1( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork.type) + ); + } + } + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case IncompleteClassComponent: + case EventTarget: + // Nothing to do for these component types + return; + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + // Unmount + var destroy = effect.destroy; + effect.destroy = undefined; + if (destroy !== undefined) { + destroy(); + } + } + if ((effect.tag & mountTag) !== NoEffect$1) { + // Mount + var create = effect.create; + effect.destroy = create(); + + { + var _destroy = effect.destroy; + if (_destroy !== undefined && typeof _destroy !== "function") { + var addendum = void 0; + if (_destroy === null) { + addendum = + " You returned null. If your effect does not require clean " + + "up, return undefined (or nothing)."; + } else if (typeof _destroy.then === "function") { + addendum = + "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " + + "Instead, write the async function inside your effect " + + "and call it immediately:\n\n" + + "useEffect(() => {\n" + + " async function fetchData() {\n" + + " // You can await here\n" + + " const response = await MyAPI.getData(someId);\n" + + " // ...\n" + + " }\n" + + " fetchData();\n" + + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + + "Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching"; + } else { + addendum = " You returned: " + _destroy; + } + warningWithoutStack$1( + false, + "An effect function must not return anything besides a function, " + + "which is used for clean-up.%s%s", + addendum, + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + } + effect = effect.next; + } while (effect !== firstEffect); + } +} + +function commitPassiveHookEffects(finishedWork) { + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); +} + +function commitLifeCycles( + finishedRoot, + current$$1, + finishedWork, + committedExpirationTime +) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountLayout, MountLayout, finishedWork); + break; + } + case ClassComponent: { + var instance = finishedWork.stateNode; + if (finishedWork.effectTag & Update) { + if (current$$1 === null) { + startPhaseTimer(finishedWork, "componentDidMount"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidMount(); + stopPhaseTimer(); + } else { + var prevProps = + finishedWork.elementType === finishedWork.type + ? current$$1.memoizedProps + : resolveDefaultProps( + finishedWork.type, + current$$1.memoizedProps + ); + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "componentDidUpdate"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + stopPhaseTimer(); + } + } + var updateQueue = finishedWork.updateQueue; + if (updateQueue !== null) { + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + commitUpdateQueue( + finishedWork, + updateQueue, + instance, + committedExpirationTime + ); + } + return; + } + case HostRoot: { + var _updateQueue = finishedWork.updateQueue; + if (_updateQueue !== null) { + var _instance = null; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostComponent: + _instance = getPublicInstance(finishedWork.child.stateNode); + break; + case ClassComponent: + _instance = finishedWork.child.stateNode; + break; + } + } + commitUpdateQueue( + finishedWork, + _updateQueue, + _instance, + committedExpirationTime + ); + } + return; + } + case HostComponent: { + var _instance2 = finishedWork.stateNode; + + // Renderers may schedule work to be done after host components are mounted + // (eg DOM renderer may schedule auto-focus for inputs and form controls). + // These effects should only be committed when components are first mounted, + // aka when there is no current/alternate. + if (current$$1 === null && finishedWork.effectTag & Update) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + commitMount(_instance2, type, props, finishedWork); + } + + return; + } + case HostText: { + // We have no life-cycles associated with text. + return; + } + case HostPortal: { + // We have no life-cycles associated with portals. + return; + } + case Profiler: { + if (enableProfilerTimer) { + var onRender = finishedWork.memoizedProps.onRender; + + if (enableSchedulerTracing) { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime(), + finishedRoot.memoizedInteractions + ); + } else { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime() + ); + } + } + return; + } + case SuspenseComponent: + case IncompleteClassComponent: + return; + case EventTarget: { + if (enableEventAPI) { + var _type = finishedWork.type.type; + var _props = finishedWork.memoizedProps; + var _instance3 = finishedWork.stateNode; + var parentInstance = null; + + var node = finishedWork.return; + // Traverse up the fiber tree until we find the parent host node. + while (node !== null) { + if (node.tag === HostComponent) { + parentInstance = node.stateNode; + break; + } else if (node.tag === HostRoot) { + parentInstance = node.stateNode.containerInfo; + break; + } + node = node.return; + } + (function() { + if (!(parentInstance !== null)) { + throw ReactError( + "This should have a parent host component initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + commitEventTarget(_type, _props, _instance3, parentInstance); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + mountEventComponent(finishedWork.stateNode); + } + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function hideOrUnhideAllChildren(finishedWork, isHidden) { + if (supportsMutation) { + // We only have the top Fiber that was inserted but we need to recurse down its + var node = finishedWork; + while (true) { + if (node.tag === HostComponent) { + var instance = node.stateNode; + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); + } + } else if (node.tag === HostText) { + var _instance4 = node.stateNode; + if (isHidden) { + hideTextInstance(_instance4); + } else { + unhideTextInstance(_instance4, node.memoizedProps); + } + } else if ( + node.tag === SuspenseComponent && + node.memoizedState !== null + ) { + // Found a nested Suspense component that timed out. Skip over the + var fallbackChildFragment = node.child.sibling; + fallbackChildFragment.return = node; + node = fallbackChildFragment; + continue; + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } +} + +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse = void 0; + switch (finishedWork.tag) { + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; + default: + instanceToUse = instance; + } + if (typeof ref === "function") { + ref(instanceToUse); + } else { + { + if (!ref.hasOwnProperty("current")) { + warningWithoutStack$1( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().%s", + getComponentName(finishedWork.type), + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + + ref.current = instanceToUse; + } + } +} + +function commitDetachRef(current$$1) { + var currentRef = current$$1.ref; + if (currentRef !== null) { + if (typeof currentRef === "function") { + currentRef(null); + } else { + currentRef.current = null; + } + } +} + +// User-originating errors (lifecycles and refs) should not interrupt +// deletion, so don't let them throw. Host-originating errors should +// interrupt deletion, so it's okay +function commitUnmount(current$$1) { + onCommitUnmount(current$$1); + + switch (current$$1.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + var updateQueue = current$$1.updateQueue; + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + var destroy = effect.destroy; + if (destroy !== undefined) { + safelyCallDestroy(current$$1, destroy); + } + effect = effect.next; + } while (effect !== firstEffect); + } + } + break; + } + case ClassComponent: { + safelyDetachRef(current$$1); + var instance = current$$1.stateNode; + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current$$1, instance); + } + return; + } + case HostComponent: { + safelyDetachRef(current$$1); + return; + } + case HostPortal: { + // TODO: this is recursive. + // We are also not using this parent because + // the portal will get pushed immediately. + if (supportsMutation) { + unmountHostComponents(current$$1); + } else if (supportsPersistence) { + emptyPortalContainer(current$$1); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + var eventComponentInstance = current$$1.stateNode; + unmountEventComponent(eventComponentInstance); + current$$1.stateNode = null; + } + } + } +} + +function commitNestedUnmounts(root) { + // While we're inside a removed host node we don't want to call + // removeChild on the inner nodes because they're removed by the top + // call anyway. We also want to call componentWillUnmount on all + // composites before this host node is removed from the tree. Therefore + var node = root; + while (true) { + commitUnmount(node); + // Visit children because they may contain more composite or host nodes. + // Skip portals because commitUnmount() currently visits them recursively. + if ( + node.child !== null && + // If we use mutation we drill down into portals using commitUnmount above. + // If we don't use mutation we drill down into portals here instead. + (!supportsMutation || node.tag !== HostPortal) + ) { + node.child.return = node; + node = node.child; + continue; + } + if (node === root) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === root) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function detachFiber(current$$1) { + // Cut off the return pointers to disconnect it from the tree. Ideally, we + // should clear the child pointer of the parent alternate to let this + // get GC:ed but we don't know which for sure which parent is the current + // one so we'll settle for GC:ing the subtree of this child. This child + // itself will be GC:ed when the parent updates the next time. + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + if (alternate !== null) { + alternate.return = null; + alternate.child = null; + alternate.memoizedState = null; + alternate.updateQueue = null; + } +} + +function emptyPortalContainer(current$$1) { + if (!supportsPersistence) { + return; + } + + var portal = current$$1.stateNode; + var containerInfo = portal.containerInfo; + + var emptyChildSet = createContainerChildSet(containerInfo); +} + +function commitContainer(finishedWork) { + if (!supportsPersistence) { + return; + } + + switch (finishedWork.tag) { + case ClassComponent: + case HostComponent: + case HostText: + case EventTarget: + case EventComponent: { + return; + } + case HostRoot: + case HostPortal: { + var portalOrRoot = finishedWork.stateNode; + var containerInfo = portalOrRoot.containerInfo, + _pendingChildren = portalOrRoot.pendingChildren; + + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function getHostParentFiber(fiber) { + var parent = fiber.return; + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + parent = parent.return; + } + (function() { + { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function isHostParent(fiber) { + return ( + fiber.tag === HostComponent || + fiber.tag === HostRoot || + fiber.tag === HostPortal + ); +} + +function getHostSibling(fiber) { + // We're going to search forward into the tree until we find a sibling host + // node. Unfortunately, if multiple insertions are done in a row we have to + // search past them. This leads to exponential search for the next sibling. + var node = fiber; + siblings: while (true) { + // If we didn't find anything, let's try the next sibling. + while (node.sibling === null) { + if (node.return === null || isHostParent(node.return)) { + // If we pop out of the root or hit the parent the fiber we are the + // last sibling. + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + while ( + node.tag !== HostComponent && + node.tag !== HostText && + node.tag !== DehydratedSuspenseComponent + ) { + // If it is not host node and, we might have a host node inside it. + // Try to search down until we find one. + if (node.effectTag & Placement) { + // If we don't have a child, try the siblings instead. + continue siblings; + } + // If we don't have a child, try the siblings instead. + // We also skip portals because they are not part of this host tree. + if (node.child === null || node.tag === HostPortal) { + continue siblings; + } else { + node.child.return = node; + node = node.child; + } + } + // Check if this host node is stable or about to be placed. + if (!(node.effectTag & Placement)) { + // Found it! + return node.stateNode; + } + } +} + +function commitPlacement(finishedWork) { + if (!supportsMutation) { + return; + } + + // Recursively insert all host nodes into the parent. + var parentFiber = getHostParentFiber(finishedWork); + + // Note: these two variables *must* always be updated together. + var parent = void 0; + var isContainer = void 0; + + switch (parentFiber.tag) { + case HostComponent: + parent = parentFiber.stateNode; + isContainer = false; + break; + case HostRoot: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + case HostPortal: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + default: + (function() { + { + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + if (parentFiber.effectTag & ContentReset) { + // Reset the text content of the parent before doing any insertions + resetTextContent(parent); + // Clear ContentReset from the effect tag + parentFiber.effectTag &= ~ContentReset; + } + + var before = getHostSibling(finishedWork); + // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + var node = finishedWork; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + var stateNode = node.stateNode; + if (before) { + if (isContainer) { + insertInContainerBefore(parent, stateNode, before); + } else { + insertBefore(parent, stateNode, before); + } + } else { + if (isContainer) { + appendChildToContainer(parent, stateNode); + } else { + appendChild(parent, stateNode); + } + } + } else if (node.tag === HostPortal) { + // If the insertion itself is a portal, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function unmountHostComponents(current$$1) { + // We only have the top Fiber that was deleted but we need to recurse down its + var node = current$$1; + + // Each iteration, currentParent is populated with node's host parent if not + // currentParentIsValid. + var currentParentIsValid = false; + + // Note: these two variables *must* always be updated together. + var currentParent = void 0; + var currentParentIsContainer = void 0; + + while (true) { + if (!currentParentIsValid) { + var parent = node.return; + findParent: while (true) { + (function() { + if (!(parent !== null)) { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + switch (parent.tag) { + case HostComponent: + currentParent = parent.stateNode; + currentParentIsContainer = false; + break findParent; + case HostRoot: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + case HostPortal: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + } + parent = parent.return; + } + currentParentIsValid = true; + } + + if (node.tag === HostComponent || node.tag === HostText) { + commitNestedUnmounts(node); + // After all the children have unmounted, it is now safe to remove the + // node from the tree. + if (currentParentIsContainer) { + removeChildFromContainer(currentParent, node.stateNode); + } else { + removeChild(currentParent, node.stateNode); + } + // Don't visit children because we already visited them. + } else if ( + enableSuspenseServerRenderer && + node.tag === DehydratedSuspenseComponent + ) { + // Delete the dehydrated suspense boundary and all of its content. + if (currentParentIsContainer) { + clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); + } else { + clearSuspenseBoundary(currentParent, node.stateNode); + } + } else if (node.tag === HostPortal) { + if (node.child !== null) { + // When we go into a portal, it becomes the parent to remove from. + // We will reassign it back when we pop the portal on the way up. + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = true; + // Visit children because portals might contain host components. + node.child.return = node; + node = node.child; + continue; + } + } else { + commitUnmount(node); + // Visit children because we may find more host components below. + if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === current$$1) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === current$$1) { + return; + } + node = node.return; + if (node.tag === HostPortal) { + // When we go out of the portal, we need to restore the parent. + // Since we don't keep a stack of them, we will search for it. + currentParentIsValid = false; + } + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function commitDeletion(current$$1) { + if (supportsMutation) { + // Recursively delete all host nodes from the parent. + // Detach refs and call componentWillUnmount() on the whole subtree. + unmountHostComponents(current$$1); + } else { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitNestedUnmounts(current$$1); + } + detachFiber(current$$1); +} + +function commitWork(current$$1, finishedWork) { + if (!supportsMutation) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + } + + commitContainer(finishedWork); + return; + } + + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case ClassComponent: { + return; + } + case HostComponent: { + var instance = finishedWork.stateNode; + if (instance != null) { + // Commit the work prepared earlier. + var newProps = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldProps = + current$$1 !== null ? current$$1.memoizedProps : newProps; + var type = finishedWork.type; + // TODO: Type the updateQueue to be specific to host components. + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + if (updatePayload !== null) { + commitUpdate( + instance, + updatePayload, + type, + oldProps, + newProps, + finishedWork + ); + } + } + return; + } + case HostText: { + (function() { + if (!(finishedWork.stateNode !== null)) { + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var textInstance = finishedWork.stateNode; + var newText = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldText = current$$1 !== null ? current$$1.memoizedProps : newText; + commitTextUpdate(textInstance, oldText, newText); + return; + } + case EventTarget: { + return; + } + case HostRoot: { + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + case IncompleteClassComponent: { + return; + } + case EventComponent: { + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + + var newDidTimeout = void 0; + var primaryChildParent = finishedWork; + if (newState === null) { + newDidTimeout = false; + } else { + newDidTimeout = true; + primaryChildParent = finishedWork.child; + if (newState.fallbackExpirationTime === NoWork) { + // If the children had not already timed out, record the time. + // This is used to compute the elapsed time during subsequent + // attempts to render the children. + // We model this as a normal pri expiration time since that's + // how we infer start time for updates. + newState.fallbackExpirationTime = computeAsyncExpirationNoBucket( + requestCurrentTime() + ); + } + } + + if (supportsMutation && primaryChildParent !== null) { + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + } + + // If this boundary just timed out, then it will have a set of thenables. + // For each thenable, attach a listener so that when it resolves, React + // attempts to re-render the boundary in the primary (pre-timeout) state. + var thenables = finishedWork.updateQueue; + if (thenables !== null) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); + } + thenables.forEach(function(thenable) { + // Memoize using the boundary fiber to prevent redundant listeners. + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + if (!retryCache.has(thenable)) { + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + retryCache.add(thenable); + thenable.then(retry, retry); + } + }); + } +} + +function commitResetTextContent(current$$1) { + if (!supportsMutation) { + return; + } + resetTextContent(current$$1.stateNode); +} + +var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; +var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; + +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + // Unmount the root by rendering null. + update.tag = CaptureUpdate; + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: null }; + var error = errorInfo.value; + update.callback = function() { + onUncaughtError(error); + logError(fiber, errorInfo); + }; + return update; +} + +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + update.tag = CaptureUpdate; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if (typeof getDerivedStateFromError === "function") { + var error = errorInfo.value; + update.payload = function() { + return getDerivedStateFromError(error); + }; + } + + var inst = fiber.stateNode; + if (inst !== null && typeof inst.componentDidCatch === "function") { + update.callback = function callback() { + if (typeof getDerivedStateFromError !== "function") { + // To preserve the preexisting retry behavior of error boundaries, + // we keep track of which ones already failed during this batch. + // This gets reset before we yield back to the browser. + // TODO: Warn in strict mode if getDerivedStateFromError is + // not defined. + markLegacyErrorBoundaryAsFailed(this); + } + var error = errorInfo.value; + var stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: stack !== null ? stack : "" + }); + { + if (typeof getDerivedStateFromError !== "function") { + // If componentDidCatch is the only error boundary method defined, + // then it needs to call setState to recover from errors. + // If no state update is scheduled then the boundary will swallow the error. + !(fiber.expirationTime === Sync) + ? warningWithoutStack$1( + false, + "%s: Error boundaries should implement getDerivedStateFromError(). " + + "In that method, return a state update to display an error message or fallback UI.", + getComponentName(fiber.type) || "Unknown" + ) + : void 0; + } + } + }; + } + return update; +} + +function attachPingListener(root, renderExpirationTime, thenable) { + // Attach a listener to the promise to "ping" the root and retry. But + // only if one does not already exist for the current render expiration + // time (which acts like a "thread ID" here). + var pingCache = root.pingCache; + var threadIDs = void 0; + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } else { + threadIDs = pingCache.get(thenable); + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } + } + if (!threadIDs.has(renderExpirationTime)) { + // Memoize using the thread ID to prevent redundant listeners. + threadIDs.add(renderExpirationTime); + var ping = pingSuspendedRoot.bind( + null, + root, + thenable, + renderExpirationTime + ); + if (enableSchedulerTracing) { + ping = tracing.unstable_wrap(ping); + } + thenable.then(ping, ping); + } +} + +function throwException( + root, + returnFiber, + sourceFiber, + value, + renderExpirationTime +) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + if ( + value !== null && + typeof value === "object" && + typeof value.then === "function" + ) { + // This is a thenable. + var thenable = value; + + // Schedule the nearest Suspense to re-render the timed out view. + var _workInProgress = returnFiber; + do { + if ( + _workInProgress.tag === SuspenseComponent && + shouldCaptureSuspense(_workInProgress) + ) { + // Found the nearest boundary. + + // Stash the promise on the boundary fiber. If the boundary times out, we'll + var thenables = _workInProgress.updateQueue; + if (thenables === null) { + var updateQueue = new Set(); + updateQueue.add(thenable); + _workInProgress.updateQueue = updateQueue; + } else { + thenables.add(thenable); + } + + // If the boundary is outside of concurrent mode, we should *not* + // suspend the commit. Pretend as if the suspended component rendered + // null and keep rendering. In the commit phase, we'll schedule a + // subsequent synchronous update to re-render the Suspense. + // + // Note: It doesn't matter whether the component that suspended was + // inside a concurrent mode tree. If the Suspense is outside of it, we + // should *not* suspend the commit. + if ((_workInProgress.mode & ConcurrentMode) === NoContext) { + _workInProgress.effectTag |= DidCapture; + + // We're going to commit this fiber even though it didn't complete. + // But we shouldn't call any lifecycle methods or callbacks. Remove + // all lifecycle effect tags. + sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); + + if (sourceFiber.tag === ClassComponent) { + var currentSourceFiber = sourceFiber.alternate; + if (currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed class component. For example, we should not call + // componentWillUnmount if it is deleted. + sourceFiber.tag = IncompleteClassComponent; + } else { + // When we try rendering again, we should not reuse the current fiber, + // since it's known to be in an inconsistent state. Use a force updte to + // prevent a bail out. + var update = createUpdate(Sync); + update.tag = ForceUpdate; + enqueueUpdate(sourceFiber, update); + } + } + + // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + sourceFiber.expirationTime = Sync; + + // Exit without suspending. + return; + } + + // Confirmed that the boundary is in a concurrent mode tree. Continue + // with the normal suspend path. + + attachPingListener(root, renderExpirationTime, thenable); + + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } else if ( + enableSuspenseServerRenderer && + _workInProgress.tag === DehydratedSuspenseComponent + ) { + attachPingListener(root, renderExpirationTime, thenable); + + // Since we already have a current fiber, we can eagerly add a retry listener. + var retryCache = _workInProgress.memoizedState; + if (retryCache === null) { + retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); + var current$$1 = _workInProgress.alternate; + (function() { + if (!current$$1) { + throw ReactError( + "A dehydrated suspense boundary must commit before trying to render. This is probably a bug in React." + ); + } + })(); + current$$1.memoizedState = retryCache; + } + // Memoize using the boundary fiber to prevent redundant listeners. + if (!retryCache.has(thenable)) { + retryCache.add(thenable); + var retry = resolveRetryThenable.bind( + null, + _workInProgress, + thenable + ); + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + thenable.then(retry, retry); + } + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } + // This boundary already captured during this render. Continue to the next + // boundary. + _workInProgress = _workInProgress.return; + } while (_workInProgress !== null); + // No boundary was found. Fallthrough to error mode. + // TODO: Use invariant so the message is stripped in prod? + value = new Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n" + + "\n" + + "Add a component higher in the tree to " + + "provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + + // We didn't find a boundary that could handle this type of exception. Start + // over and traverse parent path again, this time treating the exception + // as an error. + renderDidError(); + value = createCapturedValue(value, sourceFiber); + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + var _update = createRootErrorUpdate( + workInProgress, + _errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update); + return; + } + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + (typeof ctor.getDerivedStateFromError === "function" || + (instance !== null && + typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance))) + ) { + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + // Schedule the error boundary to re-render using updated state + var _update2 = createClassErrorUpdate( + workInProgress, + errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update2); + return; + } + break; + default: + break; + } + workInProgress = workInProgress.return; + } while (workInProgress !== null); +} + +function unwindWork(workInProgress, renderExpirationTime) { + switch (workInProgress.tag) { + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + (function() { + if (!((_effectTag & DidCapture) === NoEffect)) { + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + } + })(); + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + case HostComponent: { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } + case SuspenseComponent: { + var _effectTag2 = workInProgress.effectTag; + if (_effectTag2 & ShouldCapture) { + workInProgress.effectTag = (_effectTag2 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + return null; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // TODO: popHydrationState + var _effectTag3 = workInProgress.effectTag; + if (_effectTag3 & ShouldCapture) { + workInProgress.effectTag = + (_effectTag3 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + } + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + case EventComponent: + case EventTarget: + if (enableEventAPI) { + popHostContext(workInProgress); + } + return null; + default: + return null; + } +} + +function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + var childContextTypes = interruptedWork.type.childContextTypes; + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); + } + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } +} + +// TODO: Ahaha Andrew is bad at spellling +// DEV stuff +var ceil = Math.ceil; + +var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; +var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; +var ReactShouldWarnActingUpdates = + ReactSharedInternals.ReactShouldWarnActingUpdates; + +var NotWorking = 0; +var BatchedPhase = 1; +var LegacyUnbatchedPhase = 2; +var RenderPhase = 4; +var CommitPhase = 5; + +var RootIncomplete = 0; +var RootErrored = 1; +var RootSuspended = 2; +var RootCompleted = 3; + +// The phase of work we're currently in +var workPhase = NotWorking; +// The root we're working on +var workInProgressRoot = null; +// The fiber we're working on +var workInProgress = null; +// The expiration time we're rendering +var renderExpirationTime = NoWork; +// Whether to root completed, errored, suspended, etc. +var workInProgressRootExitStatus = RootIncomplete; +// Most recent event time among processed updates during this render. +// This is conceptually a time stamp but expressed in terms of an ExpirationTime +// because we deal mostly with expiration times in the hot path, so this avoids +// the conversion happening in the hot path. +var workInProgressRootMostRecentEventTime = Sync; + +var nextEffect = null; +var hasUncaughtError = false; +var firstUncaughtError = null; +var legacyErrorBoundariesThatAlreadyFailed = null; + +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsExpirationTime = NoWork; + +var rootsWithPendingDiscreteUpdates = null; + +// Use these to prevent an infinite loop of nested updates +var NESTED_UPDATE_LIMIT = 50; +var nestedUpdateCount = 0; +var rootWithNestedUpdates = null; + +var NESTED_PASSIVE_UPDATE_LIMIT = 50; +var nestedPassiveUpdateCount = 0; + +var interruptedBy = null; + +// Expiration times are computed by adding to the current time (the start +// time). However, if two updates are scheduled within the same event, we +// should treat their start times as simultaneous, even if the actual clock +// time has advanced between the first and second call. + +// In other words, because expiration times determine how updates are batched, +// we want all updates of like priority that occur within the same event to +// receive the same expiration time. Otherwise we get tearing. +var currentEventTime = NoWork; + +function requestCurrentTime() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // We're inside React, so it's fine to read the actual time. + return msToExpirationTime(now()); + } + // We're not inside React, so we may be in the middle of a browser event. + if (currentEventTime !== NoWork) { + // Use the same start time for all updates until we enter React again. + return currentEventTime; + } + // This is the first update since React yielded. Compute a new start time. + currentEventTime = msToExpirationTime(now()); + return currentEventTime; +} + +function computeExpirationForFiber(currentTime, fiber) { + if ((fiber.mode & ConcurrentMode) === NoContext) { + return Sync; + } + + if (workPhase === RenderPhase) { + // Use whatever time we're already rendering + return renderExpirationTime; + } + + // Compute an expiration time based on the Scheduler priority. + var expirationTime = void 0; + var priorityLevel = getCurrentPriorityLevel(); + switch (priorityLevel) { + case ImmediatePriority: + expirationTime = Sync; + break; + case UserBlockingPriority: + // TODO: Rename this to computeUserBlockingExpiration + expirationTime = computeInteractiveExpiration(currentTime); + break; + case NormalPriority: + case LowPriority: + // TODO: Handle LowPriority + // TODO: Rename this to... something better. + expirationTime = computeAsyncExpiration(currentTime); + break; + case IdlePriority: + expirationTime = Never; + break; + default: + (function() { + { + throw ReactError("Expected a valid priority level"); + } + })(); + } + + // If we're in the middle of rendering a tree, do not update at the same + // expiration time that is already rendering. + if (workInProgressRoot !== null && expirationTime === renderExpirationTime) { + // This is a trick to move this update into a separate batch + expirationTime -= 1; + } + + return expirationTime; +} + +function scheduleUpdateOnFiber(fiber, expirationTime) { + checkForNestedUpdates(); + warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber); + + var root = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (root === null) { + warnAboutUpdateOnUnmountedFiberInDEV(fiber); + return; + } + + root.pingTime = NoWork; + + checkForInterruption(fiber, expirationTime); + recordScheduleUpdate(); + + if (expirationTime === Sync) { + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. The initial mount of a ReactDOM.render-ed + // root inside of batchedUpdates should be synchronous, but layout updates + // should be deferred until the end of the batch. + var callback = renderRoot(root, Sync, true); + while (callback !== null) { + callback = callback(true); + } + } else { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + if (workPhase === NotWorking) { + // Flush the synchronous work now, wnless we're already working or inside + // a batch. This is intentionally inside scheduleUpdateOnFiber instead of + // scheduleCallbackForFiber to preserve the ability to schedule a callback + // without immediately flushing it. We only do this for user-initated + // updates, to preserve historical behavior of sync mode. + flushImmediateQueue(); + } + } + } else { + // TODO: computeExpirationForFiber also reads the priority. Pass the + // priority as an argument to that function and this one. + var priorityLevel = getCurrentPriorityLevel(); + if (priorityLevel === UserBlockingPriority) { + // This is the result of a discrete event. Track the lowest priority + // discrete update per root so we can flush them early, if needed. + if (rootsWithPendingDiscreteUpdates === null) { + rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]); + } else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root); + if ( + lastDiscreteTime === undefined || + lastDiscreteTime > expirationTime + ) { + rootsWithPendingDiscreteUpdates.set(root, expirationTime); + } + } + } + scheduleCallbackForRoot(root, priorityLevel, expirationTime); + } +} +var scheduleWork = scheduleUpdateOnFiber; + +// This is split into a separate function so we can mark a fiber with pending +// work without treating it as a typical update that originates from an event; +// e.g. retrying a Suspense boundary isn't an update, but it does schedule work +// on a fiber. +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + // Update the source fiber's expiration time + if (fiber.expirationTime < expirationTime) { + fiber.expirationTime = expirationTime; + } + var alternate = fiber.alternate; + if (alternate !== null && alternate.expirationTime < expirationTime) { + alternate.expirationTime = expirationTime; + } + // Walk the parent path to the root and update the child expiration time. + var node = fiber.return; + var root = null; + if (node === null && fiber.tag === HostRoot) { + root = fiber.stateNode; + } else { + while (node !== null) { + alternate = node.alternate; + if (node.childExpirationTime < expirationTime) { + node.childExpirationTime = expirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + if (node.return === null && node.tag === HostRoot) { + root = node.stateNode; + break; + } + node = node.return; + } + } + + if (root !== null) { + // Update the first and last pending expiration times in this root + var firstPendingTime = root.firstPendingTime; + if (expirationTime > firstPendingTime) { + root.firstPendingTime = expirationTime; + } + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime === NoWork || expirationTime < lastPendingTime) { + root.lastPendingTime = expirationTime; + } + } + + return root; +} + +// Use this function, along with runRootCallback, to ensure that only a single +// callback per root is scheduled. It's still possible to call renderRoot +// directly, but scheduling via this function helps avoid excessive callbacks. +// It works by storing the callback node and expiration time on the root. When a +// new callback comes in, it compares the expiration time to determine if it +// should cancel the previous one. It also relies on commitRoot scheduling a +// callback to render the next level, because that means we don't need a +// separate callback per expiration time. +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + var existingCallbackExpirationTime = root.callbackExpirationTime; + if (existingCallbackExpirationTime < expirationTime) { + // New callback has higher priority than the existing one. + var existingCallbackNode = root.callbackNode; + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + root.callbackExpirationTime = expirationTime; + + var options = null; + if (expirationTime !== Sync && expirationTime !== Never) { + var timeout = expirationTimeToMs(expirationTime) - now(); + if (timeout > 5000) { + // Sanity check. Should never take longer than 5 seconds. + // TODO: Add internal warning? + timeout = 5000; + } + options = { timeout: timeout }; + } + + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + options + ); + if ( + enableUserTimingAPI && + expirationTime !== Sync && + workPhase !== RenderPhase && + workPhase !== CommitPhase + ) { + // Scheduled an async callback, and we're not already working. Add an + // entry to the flamegraph that shows we're waiting for a callback + // to fire. + startRequestCallbackTimer(); + } + } + + // Add the current set of interactions to the pending set associated with + // this root. + schedulePendingInteraction(root, expirationTime); +} + +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode; + var continuation = null; + try { + continuation = callback(isSync); + if (continuation !== null) { + return runRootCallback.bind(null, root, continuation); + } else { + return null; + } + } finally { + // If the callback exits without returning a continuation, remove the + // corresponding callback node from the root. Unless the callback node + // has changed, which implies that it was already cancelled by a high + // priority update. + if (continuation === null && prevCallbackNode === root.callbackNode) { + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + } + } +} + +function flushInteractiveUpdates$1() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // Can't synchronously flush interactive updates if React is already + // working. This is currently a no-op. + // TODO: Should we fire a warning? This happens if you synchronously invoke + // an input event inside an effect, like with `element.click()`. + return; + } + flushPendingDiscreteUpdates(); +} + +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + if ( + firstBatch !== null && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ) { + root.finishedWork = root.current.alternate; + root.pendingCommitExpirationTime = expirationTime; + scheduleCallback(NormalPriority, function() { + firstBatch._onComplete(); + return null; + }); + return true; + } else { + return false; + } +} + +function interactiveUpdates$1(fn, a, b, c) { + if (workPhase === NotWorking) { + // TODO: Remove this call. Instead of doing this automatically, the caller + // should explicitly call flushInteractiveUpdates. + flushPendingDiscreteUpdates(); + } + return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c)); +} + +function flushPendingDiscreteUpdates() { + if (rootsWithPendingDiscreteUpdates !== null) { + // For each root with pending discrete updates, schedule a callback to + // immediately flush them. + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + }); + // Now flush the immediate queue. + flushImmediateQueue(); + } +} + +function batchedUpdates$1(fn, a) { + if (workPhase !== NotWorking) { + // We're already working, or inside a batch, so batchedUpdates is a no-op. + return fn(a); + } + workPhase = BatchedPhase; + try { + return fn(a); + } finally { + workPhase = NotWorking; + // Flush the immediate callbacks that were scheduled during this batch + flushImmediateQueue(); + } +} + +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = NoWork; + + var timeoutHandle = root.timeoutHandle; + if (timeoutHandle !== noTimeout) { + // The root previous suspended and scheduled a timeout to commit a fallback + // state. Now that we have additional work, cancel the timeout. + root.timeoutHandle = noTimeout; + // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + cancelTimeout(timeoutHandle); + } + + if (workInProgress !== null) { + var interruptedWork = workInProgress.return; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork.return; + } + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = Sync; + + { + ReactStrictModeWarnings.discardPendingWarnings(); + } +} + +function renderRoot(root, expirationTime, isSync) { + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + + if (enableUserTimingAPI && expirationTime !== Sync) { + var didExpire = isSync; + stopRequestCallbackTimer(didExpire); + } + + if (root.firstPendingTime < expirationTime) { + // If there's no work left at this expiration time, exit immediately. This + // happens when multiple callbacks are scheduled for a single root, but an + // earlier callback flushes the work of a later one. + return null; + } + + if (root.pendingCommitExpirationTime === expirationTime) { + // There's already a pending commit at this expiration time. + root.pendingCommitExpirationTime = NoWork; + return commitRoot.bind(null, root, expirationTime); + } + + flushPassiveEffects(); + + // If the root or expiration time have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) { + prepareFreshStack(root, expirationTime); + startWorkOnPendingInteraction(root, expirationTime); + } + + // If we have a work-in-progress fiber, it means there's still work to do + // in this root. + if (workInProgress !== null) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + if (prevDispatcher === null) { + // The React isomorphic package does not include a default dispatcher. + // Instead the first renderer will lazily attach one, in order to give + // nicer error messages. + prevDispatcher = ContextOnlyDispatcher; + } + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + startWorkLoopTimer(workInProgress); + + // TODO: Fork renderRoot into renderRootSync and renderRootAsync + if (isSync) { + if (expirationTime !== Sync) { + // An async update expired. There may be other expired updates on + // this root. We should render all the expired work in a + // single batch. + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) { + // Restart at the current time. + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + return renderRoot.bind(null, root, currentTime); + } + } + } else { + // Since we know we're in a React event, we can clear the current + // event time. The next update will compute a new event time. + currentEventTime = NoWork; + } + + do { + try { + if (isSync) { + workLoopSync(); + } else { + workLoop(); + } + break; + } catch (thrownValue) { + // Reset module-level state that was set during the render phase. + resetContextDependences(); + resetHooks(); + + var sourceFiber = workInProgress; + if (sourceFiber === null || sourceFiber.return === null) { + // Expected to be working on a non-root fiber. This is a fatal error + // because there's no ancestor that can handle it; the root is + // supposed to capture all errors that weren't caught by an error + // boundary. + prepareFreshStack(root, expirationTime); + workPhase = prevWorkPhase; + throw thrownValue; + } + + if (enableProfilerTimer && sourceFiber.mode & ProfileMode) { + // Record the time spent rendering before an error was thrown. This + // avoids inaccurate Profiler durations in the case of a + // suspended render. + stopProfilerTimerIfRunningAndRecordDelta(sourceFiber, true); + } + + var returnFiber = sourceFiber.return; + throwException( + root, + returnFiber, + sourceFiber, + thrownValue, + renderExpirationTime + ); + workInProgress = completeUnitOfWork(sourceFiber); + } + } while (true); + + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + + if (workInProgress !== null) { + // There's still work left over. Return a continuation. + stopInterruptedWorkLoopTimer(); + if (expirationTime !== Sync) { + startRequestCallbackTimer(); + } + return renderRoot.bind(null, root, expirationTime); + } + } + + // We now have a consistent tree. The next step is either to commit it, or, if + // something suspended, wait to commit it after a timeout. + stopFinishedWorkLoopTimer(); + + var isLocked = resolveLocksOnRoot(root, expirationTime); + if (isLocked) { + // This root has a lock that prevents it from committing. Exit. If we begin + // work on the root again, without any intervening updates, it will finish + // without doing additional work. + return null; + } + + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + + switch (workInProgressRootExitStatus) { + case RootIncomplete: { + (function() { + { + throw ReactError("Should have a work-in-progress."); + } + })(); + } + // Flow knows about invariant, so it compains if I add a break statement, + // but eslint doesn't know about invariant, so it complains if I do. + // eslint-disable-next-line no-fallthrough + case RootErrored: { + // An error was thrown. First check if there is lower priority work + // scheduled on this root. + var lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. Before raising the error, try rendering + // at the lower priority to see if it fixes it. Use a continuation to + // maintain the existing priority and position in the queue. + return renderRoot.bind(null, root, lastPendingTime); + } + if (!isSync) { + // If we're rendering asynchronously, it's possible the error was + // caused by tearing due to a mutation during an event. Try rendering + // one more time without yiedling to events. + prepareFreshStack(root, expirationTime); + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + return null; + } + // If we're already rendering synchronously, commit the root in its + // errored state. + return commitRoot.bind(null, root, expirationTime); + } + case RootSuspended: { + if (!isSync) { + var _lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. It might be unsuspended. Try rendering + // at that level. + return renderRoot.bind(null, root, _lastPendingTime); + } + // If workInProgressRootMostRecentEventTime is Sync, that means we didn't + // track any event times. That can happen if we retried but nothing switched + // from fallback to content. There's no reason to delay doing no work. + if (workInProgressRootMostRecentEventTime !== Sync) { + var msUntilTimeout = computeMsUntilTimeout( + workInProgressRootMostRecentEventTime, + expirationTime + ); + // Don't bother with a very short suspense time. + if (msUntilTimeout > 10) { + // The render is suspended, it hasn't timed out, and there's no lower + // priority work to do. Instead of committing the fallback + // immediately, wait for more data to arrive. + root.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root, expirationTime), + msUntilTimeout + ); + return null; + } + } + } + // The work expired. Commit immediately. + return commitRoot.bind(null, root, expirationTime); + } + case RootCompleted: { + // The work completed. Ready to commit. + return commitRoot.bind(null, root, expirationTime); + } + default: { + (function() { + { + throw ReactError("Unknown root exit status."); + } + })(); + } + } +} + +function markRenderEventTime(expirationTime) { + if (expirationTime < workInProgressRootMostRecentEventTime) { + workInProgressRootMostRecentEventTime = expirationTime; + } +} + +function renderDidSuspend() { + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootSuspended; + } +} + +function renderDidError() { + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) { + workInProgressRootExitStatus = RootErrored; + } +} + +function inferTimeFromExpirationTime(expirationTime) { + // We don't know exactly when the update was scheduled, but we can infer an + // approximate start time from the expiration time. + var earliestExpirationTimeMs = expirationTimeToMs(expirationTime); + return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; +} + +function workLoopSync() { + // Already timed out, so perform work without checking if we need to yield. + while (workInProgress !== null) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function workLoop() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function performUnitOfWork(unitOfWork) { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = unitOfWork.alternate; + + startWorkTimer(unitOfWork); + setCurrentFiber(unitOfWork); + + var next = void 0; + if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoContext) { + startProfilerTimer(unitOfWork); + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + } + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (next === null) { + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(unitOfWork); + } + + ReactCurrentOwner$2.current = null; + return next; +} + +function completeUnitOfWork(unitOfWork) { + // Attempt to complete the current unit of work, then move to the next + // sibling. If there are no more siblings, return to the parent fiber. + workInProgress = unitOfWork; + do { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = workInProgress.alternate; + var returnFiber = workInProgress.return; + + // Check if the work completed or if something threw. + if ((workInProgress.effectTag & Incomplete) === NoEffect) { + setCurrentFiber(workInProgress); + var next = void 0; + if ( + !enableProfilerTimer || + (workInProgress.mode & ProfileMode) === NoContext + ) { + next = completeWork(current$$1, workInProgress, renderExpirationTime); + } else { + startProfilerTimer(workInProgress); + next = completeWork(current$$1, workInProgress, renderExpirationTime); + // Update render duration assuming we didn't error. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + } + stopWorkTimer(workInProgress); + resetCurrentFiber(); + resetChildExpirationTime(workInProgress); + + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + return next; + } + + if ( + returnFiber !== null && + // Do not append effects to parents if a sibling failed to complete + (returnFiber.effectTag & Incomplete) === NoEffect + ) { + // Append all the effects of the subtree and this fiber onto the effect + // list of the parent. The completion order of the children affects the + // side-effect order. + if (returnFiber.firstEffect === null) { + returnFiber.firstEffect = workInProgress.firstEffect; + } + if (workInProgress.lastEffect !== null) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; + } + returnFiber.lastEffect = workInProgress.lastEffect; + } + + // If this fiber had side-effects, we append it AFTER the children's + // side-effects. We can perform certain side-effects earlier if needed, + // by doing multiple passes over the effect list. We don't want to + // schedule our own side-effect on our own list because if end up + // reusing children we'll schedule this effect onto itself since we're + // at the end. + var effectTag = workInProgress.effectTag; + + // Skip both NoWork and PerformedWork tags when creating the effect + // list. PerformedWork effect is read by React DevTools but shouldn't be + // committed. + if (effectTag > PerformedWork) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress; + } else { + returnFiber.firstEffect = workInProgress; + } + returnFiber.lastEffect = workInProgress; + } + } + } else { + // This fiber did not complete because something threw. Pop values off + // the stack without entering the complete phase. If this is a boundary, + // capture values if possible. + var _next = unwindWork(workInProgress, renderExpirationTime); + + // Because this fiber did not complete, don't reset its expiration time. + + if ( + enableProfilerTimer && + (workInProgress.mode & ProfileMode) !== NoContext + ) { + // Record the render duration for the fiber that errored. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + + // Include the time spent working on failed children before continuing. + var actualDuration = workInProgress.actualDuration; + var child = workInProgress.child; + while (child !== null) { + actualDuration += child.actualDuration; + child = child.sibling; + } + workInProgress.actualDuration = actualDuration; + } + + if (_next !== null) { + // If completing this work spawned new work, do that next. We'll come + // back here again. + // Since we're restarting, remove anything that is not a host effect + // from the effect tag. + // TODO: The name stopFailedWorkTimer is misleading because Suspense + // also captures and restarts. + stopFailedWorkTimer(workInProgress); + _next.effectTag &= HostEffectMask; + return _next; + } + stopWorkTimer(workInProgress); + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its effect list. + returnFiber.firstEffect = returnFiber.lastEffect = null; + returnFiber.effectTag |= Incomplete; + } + } + + var siblingFiber = workInProgress.sibling; + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } + // Otherwise, return to the parent + workInProgress = returnFiber; + } while (workInProgress !== null); + + // We've reached the root. + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootCompleted; + } + return null; +} + +function resetChildExpirationTime(completedWork) { + if ( + renderExpirationTime !== Never && + completedWork.childExpirationTime === Never + ) { + // The children of this component are hidden. Don't bubble their + // expiration times. + return; + } + + var newChildExpirationTime = NoWork; + + // Bubble up the earliest expiration time. + if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoContext) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var actualDuration = completedWork.actualDuration; + var treeBaseDuration = completedWork.selfBaseDuration; + + // When a fiber is cloned, its actualDuration is reset to 0. This value will + // only be updated if work is done on the fiber (i.e. it doesn't bailout). + // When work is done, it should bubble to the parent's actualDuration. If + // the fiber has not been cloned though, (meaning no work was done), then + // this value will reflect the amount of time spent working on a previous + // render. In that case it should not bubble. We determine whether it was + // cloned by comparing the child pointer. + var shouldBubbleActualDurations = + completedWork.alternate === null || + completedWork.child !== completedWork.alternate.child; + + var child = completedWork.child; + while (child !== null) { + var childUpdateExpirationTime = child.expirationTime; + var childChildExpirationTime = child.childExpirationTime; + if (childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childUpdateExpirationTime; + } + if (childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childChildExpirationTime; + } + if (shouldBubbleActualDurations) { + actualDuration += child.actualDuration; + } + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; + while (_child !== null) { + var _childUpdateExpirationTime = _child.expirationTime; + var _childChildExpirationTime = _child.childExpirationTime; + if (_childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childUpdateExpirationTime; + } + if (_childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childChildExpirationTime; + } + _child = _child.sibling; + } + } + + completedWork.childExpirationTime = newChildExpirationTime; +} + +function commitRoot(root, expirationTime) { + runWithPriority( + ImmediatePriority, + commitRootImpl.bind(null, root, expirationTime) + ); + // If there are passive effects, schedule a callback to flush them. This goes + // outside commitRootImpl so that it inherits the priority of the render. + if (rootWithPendingPassiveEffects !== null) { + var priorityLevel = getCurrentPriorityLevel(); + scheduleCallback(priorityLevel, function() { + flushPassiveEffects(); + return null; + }); + } + return null; +} + +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + flushRenderPhaseStrictModeWarningsInDEV(); + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + var finishedWork = root.current.alternate; + (function() { + if (!(finishedWork !== null)) { + throw ReactError("Should have a work-in-progress root."); + } + })(); + + // commitRoot never returns a continuation; it always finishes synchronously. + // So we can clear these now to allow a new callback to be scheduled. + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + + startCommitTimer(); + + // Update the first and last pending times on this root. The new first + // pending time is whatever is left on the root fiber. + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; + var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + var firstPendingTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = firstPendingTimeBeforeCommit; + if (firstPendingTimeBeforeCommit < root.lastPendingTime) { + // This usually means we've finished all the work, but it can also happen + // when something gets downprioritized during render, like a hidden tree. + root.lastPendingTime = firstPendingTimeBeforeCommit; + } + + if (root === workInProgressRoot) { + // We can reset these now that they are finished. + workInProgressRoot = null; + workInProgress = null; + renderExpirationTime = NoWork; + } else { + } + // This indicates that the last root we worked on is not the same one that + // we're committing now. This most commonly happens when a suspended root + // times out. + + // Get the list of effects. + var firstEffect = void 0; + if (finishedWork.effectTag > PerformedWork) { + // A fiber's effect list consists only of its children, not itself. So if + // the root has an effect, we need to add it to the end of the list. The + // resulting list is the set that would belong to the root's parent, if it + // had one; that is, all the effects in the tree including the root. + if (finishedWork.lastEffect !== null) { + finishedWork.lastEffect.nextEffect = finishedWork; + firstEffect = finishedWork.firstEffect; + } else { + firstEffect = finishedWork; + } + } else { + // There is no effect on the root. + firstEffect = finishedWork.firstEffect; + } + + if (firstEffect !== null) { + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + // Reset this to null before calling lifecycles + ReactCurrentOwner$2.current = null; + + // The commit phase is broken into several sub-phases. We do a separate pass + // of the effect list for each phase: all mutation effects come before all + // layout effects, and so on. + + // The first phase a "before mutation" phase. We use this phase to read the + // state of the host tree right before we mutate it. This is where + // getSnapshotBeforeUpdate is called. + startCommitSnapshotEffectsTimer(); + prepareForCommit(root.containerInfo); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitBeforeMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitSnapshotEffectsTimer(); + + if (enableProfilerTimer) { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + } + + // The next phase is the mutation phase, where we mutate the host tree. + startCommitHostEffectsTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitHostEffectsTimer(); + resetAfterCommit(root.containerInfo); + + // The work-in-progress tree is now the current tree. This must come after + // the mutation phase, so that the previous tree is still current during + // componentWillUnmount, but before the layout phase, so that the finished + // work is current during componentDidMount/Update. + root.current = finishedWork; + + // The next phase is the layout phase, where we call effects that read + // the host tree after it's been mutated. The idiomatic use case for this is + // layout, but class component lifecycles also fire here for legacy reasons. + startCommitLifeCyclesTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback( + null, + commitLayoutEffects, + null, + root, + expirationTime + ); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error2 = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error2); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitLifeCyclesTimer(); + + nextEffect = null; + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + workPhase = prevWorkPhase; + } else { + // No effects. + root.current = finishedWork; + // Measure these anyway so the flamegraph explicitly shows that there were + // no effects. + // TODO: Maybe there's a better way to report this. + startCommitSnapshotEffectsTimer(); + stopCommitSnapshotEffectsTimer(); + if (enableProfilerTimer) { + recordCommitTime(); + } + startCommitHostEffectsTimer(); + stopCommitHostEffectsTimer(); + startCommitLifeCyclesTimer(); + stopCommitLifeCyclesTimer(); + } + + stopCommitTimer(); + + if (rootDoesHavePassiveEffects) { + // This commit has passive effects. Stash a reference to them. But don't + // schedule a callback until after flushing layout work. + rootDoesHavePassiveEffects = false; + rootWithPendingPassiveEffects = root; + pendingPassiveEffectsExpirationTime = expirationTime; + } else { + if (enableSchedulerTracing) { + // If there are no passive effects, then we can complete the pending + // interactions. Otherwise, we'll wait until after the passive effects + // are flushed. + finishPendingInteractions(root, expirationTime); + } + } + + // Check if there's remaining work on this root + var remainingExpirationTime = root.firstPendingTime; + if (remainingExpirationTime !== NoWork) { + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + remainingExpirationTime + ); + scheduleCallbackForRoot(root, priorityLevel, remainingExpirationTime); + } else { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } + + onCommitRoot(finishedWork.stateNode); + + if (remainingExpirationTime === Sync) { + // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; + } + } else { + nestedUpdateCount = 0; + } + + if (hasUncaughtError) { + hasUncaughtError = false; + var _error3 = firstUncaughtError; + firstUncaughtError = null; + throw _error3; + } + + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. We just committed the initial mount of + // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired + // synchronously, but layout updates should be deferred until the end + // of the batch. + return null; + } + + // If layout work was scheduled, flush it now. + flushImmediateQueue(); + return null; +} + +function commitBeforeMutationEffects() { + while (nextEffect !== null) { + if ((nextEffect.effectTag & Snapshot) !== NoEffect) { + setCurrentFiber(nextEffect); + recordEffect(); + + var current$$1 = nextEffect.alternate; + commitBeforeMutationLifeCycles(current$$1, nextEffect); + + resetCurrentFiber(); + } + nextEffect = nextEffect.nextEffect; + } +} + +function commitMutationEffects() { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & ContentReset) { + commitResetTextContent(nextEffect); + } + + if (effectTag & Ref) { + var current$$1 = nextEffect.alternate; + if (current$$1 !== null) { + commitDetachRef(current$$1); + } + } + + // The following switch statement is only concerned about placement, + // updates, and deletions. To avoid needing to add a case for every possible + // bitmap value, we remove the secondary effects from the effect tag and + // switch on that value. + var primaryEffectTag = effectTag & (Placement | Update | Deletion); + switch (primaryEffectTag) { + case Placement: { + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + // TODO: findDOMNode doesn't rely on this any more but isMounted does + // and isMounted is deprecated anyway so we should be able to kill this. + nextEffect.effectTag &= ~Placement; + break; + } + case PlacementAndUpdate: { + // Placement + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + nextEffect.effectTag &= ~Placement; + + // Update + var _current = nextEffect.alternate; + commitWork(_current, nextEffect); + break; + } + case Update: { + var _current2 = nextEffect.alternate; + commitWork(_current2, nextEffect); + break; + } + case Deletion: { + commitDeletion(nextEffect); + break; + } + } + + // TODO: Only record a mutation effect if primaryEffectTag is non-zero. + recordEffect(); + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function commitLayoutEffects(root, committedExpirationTime) { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & (Update | Callback)) { + recordEffect(); + var current$$1 = nextEffect.alternate; + commitLifeCycles(root, current$$1, nextEffect, committedExpirationTime); + } + + if (effectTag & Ref) { + recordEffect(); + commitAttachRef(nextEffect); + } + + if (effectTag & Passive) { + rootDoesHavePassiveEffects = true; + } + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function flushPassiveEffects() { + if (rootWithPendingPassiveEffects === null) { + return false; + } + var root = rootWithPendingPassiveEffects; + var expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = NoWork; + + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Cannot flush passive effects while already rendering."); + } + })(); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + + // Note: This currently assumes there are no passive effects on the root + // fiber, because the root is not part of its own effect list. This could + // change in the future. + var effect = root.current.firstEffect; + while (effect !== null) { + { + setCurrentFiber(effect); + invokeGuardedCallback(null, commitPassiveHookEffects, null, effect); + if (hasCaughtError()) { + (function() { + if (!(effect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(effect, error); + } + resetCurrentFiber(); + } + effect = effect.nextEffect; + } + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + } + + workPhase = prevWorkPhase; + flushImmediateQueue(); + + // If additional passive effects were scheduled, increment a counter. If this + // exceeds the limit, we'll fire a warning. + nestedPassiveUpdateCount = + rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1; + + return true; +} + +function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); +} + +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} + +function prepareToThrowUncaughtError(error) { + if (!hasUncaughtError) { + hasUncaughtError = true; + firstUncaughtError = error; + } +} +var onUncaughtError = prepareToThrowUncaughtError; + +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber, errorInfo, Sync); + enqueueUpdate(rootFiber, update); + var root = markUpdateTimeFromFiberToRoot(rootFiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } +} + +function captureCommitPhaseError(sourceFiber, error) { + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + return; + } + + var fiber = sourceFiber.return; + while (fiber !== null) { + if (fiber.tag === HostRoot) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + return; + } else if (fiber.tag === ClassComponent) { + var ctor = fiber.type; + var instance = fiber.stateNode; + if ( + typeof ctor.getDerivedStateFromError === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createClassErrorUpdate( + fiber, + errorInfo, + // TODO: This is always sync + Sync + ); + enqueueUpdate(fiber, update); + var root = markUpdateTimeFromFiberToRoot(fiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } + return; + } + } + fiber = fiber.return; + } +} + +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + if (pingCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(thenable); + } + + if (workInProgressRoot === root && renderExpirationTime === suspendedTime) { + // Received a ping at the same priority level at which we're currently + // rendering. Restart from the root. Don't need to schedule a ping because + // we're already working on this tree. + prepareFreshStack(root, renderExpirationTime); + return; + } + + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime < suspendedTime) { + // The root is no longer suspended at this time. + return; + } + + var pingTime = root.pingTime; + if (pingTime !== NoWork && pingTime < suspendedTime) { + // There's already a lower priority ping scheduled. + return; + } + + // Mark the time at which this ping was scheduled. + root.pingTime = suspendedTime; + + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + suspendedTime + ); + scheduleCallbackForRoot(root, priorityLevel, suspendedTime); +} + +function retryTimedOutBoundary(boundaryFiber) { + // The boundary fiber (a Suspense component) previously timed out and was + // rendered in its fallback state. One of the promises that suspended it has + // resolved, which means at least part of the tree was likely unblocked. Try + // rendering again, at a new expiration time. + var currentTime = requestCurrentTime(); + var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); + // TODO: Special case idle priority? + var priorityLevel = inferPriorityFromExpirationTime(currentTime, retryTime); + var root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime); + if (root !== null) { + scheduleCallbackForRoot(root, priorityLevel, retryTime); + } +} + +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = void 0; + if (enableSuspenseServerRenderer) { + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + break; + case DehydratedSuspenseComponent: + retryCache = boundaryFiber.memoizedState; + break; + default: + (function() { + { + throw ReactError( + "Pinged unknown suspense boundary type. This is probably a bug in React." + ); + } + })(); + } + } else { + retryCache = boundaryFiber.stateNode; + } + + if (retryCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(thenable); + } + + retryTimedOutBoundary(boundaryFiber); +} + +// Computes the next Just Noticeable Difference (JND) boundary. +// The theory is that a person can't tell the difference between small differences in time. +// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable +// difference in the experience. However, waiting for longer might mean that we can avoid +// showing an intermediate loading state. The longer we have already waited, the harder it +// is to tell small differences in time. Therefore, the longer we've already waited, +// the longer we can wait additionally. At some point we have to give up though. +// We pick a train model where the next boundary commits at a consistent schedule. +// These particular numbers are vague estimates. We expect to adjust them based on research. +function jnd(timeElapsed) { + return timeElapsed < 120 + ? 120 + : timeElapsed < 480 + ? 480 + : timeElapsed < 1080 + ? 1080 + : timeElapsed < 1920 + ? 1920 + : timeElapsed < 3000 + ? 3000 + : timeElapsed < 4320 + ? 4320 + : ceil(timeElapsed / 1960) * 1960; +} + +function computeMsUntilTimeout(mostRecentEventTime, committedExpirationTime) { + if (disableYielding) { + // Timeout immediately when yielding is disabled. + return 0; + } + + var eventTimeMs = inferTimeFromExpirationTime(mostRecentEventTime); + var currentTimeMs = now(); + var timeElapsed = currentTimeMs - eventTimeMs; + + var msUntilTimeout = jnd(timeElapsed) - timeElapsed; + + // Compute the time until this render pass would expire. + var timeUntilExpirationMs = + expirationTimeToMs(committedExpirationTime) - currentTimeMs; + + // Clamp the timeout to the expiration time. + // TODO: Once the event time is exact instead of inferred from expiration time + // we don't need this. + if (timeUntilExpirationMs < msUntilTimeout) { + msUntilTimeout = timeUntilExpirationMs; + } + + // This is the value that is passed to `setTimeout`. + return msUntilTimeout; +} + +function checkForNestedUpdates() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + rootWithNestedUpdates = null; + (function() { + { + throw ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + ); + } + })(); + } + + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + warning$1( + false, + "Maximum update depth exceeded. This can happen when a component " + + "calls setState inside useEffect, but useEffect either doesn't " + + "have a dependency array, or one of the dependencies changes on " + + "every render." + ); + } + } +} + +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + ReactStrictModeWarnings.flushLegacyContextWarning(); + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.flushPendingDeprecationWarnings(); + } + } +} + +function stopFinishedWorkLoopTimer() { + var didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function stopInterruptedWorkLoopTimer() { + // TODO: Track which fiber caused the interruption. + var didCompleteRoot = false; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function checkForInterruption(fiberThatReceivedUpdate, updateExpirationTime) { + if ( + enableUserTimingAPI && + workInProgressRoot !== null && + updateExpirationTime > renderExpirationTime + ) { + interruptedBy = fiberThatReceivedUpdate; + } +} + +var didWarnStateUpdateForUnmountedComponent = null; +function warnAboutUpdateOnUnmountedFiberInDEV(fiber) { + { + var tag = fiber.tag; + if ( + tag !== HostRoot && + tag !== ClassComponent && + tag !== FunctionComponent && + tag !== ForwardRef && + tag !== MemoComponent && + tag !== SimpleMemoComponent + ) { + // Only warn for user-defined components, not internal ones like Suspense. + return; + } + // We show the whole stack but dedupe on the top component's name because + // the problematic code almost always lies inside that component. + var componentName = getComponentName(fiber.type) || "ReactComponent"; + if (didWarnStateUpdateForUnmountedComponent !== null) { + if (didWarnStateUpdateForUnmountedComponent.has(componentName)) { + return; + } + didWarnStateUpdateForUnmountedComponent.add(componentName); + } else { + didWarnStateUpdateForUnmountedComponent = new Set([componentName]); + } + warningWithoutStack$1( + false, + "Can't perform a React state update on an unmounted component. This " + + "is a no-op, but it indicates a memory leak in your application. To " + + "fix, cancel all subscriptions and asynchronous tasks in %s.%s", + tag === ClassComponent + ? "the componentWillUnmount method" + : "a useEffect cleanup function", + getStackByFiberInDevAndProd(fiber) + ); + } +} + +var beginWork$$1 = void 0; +if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + var dummyFiber = null; + beginWork$$1 = function(current$$1, unitOfWork, expirationTime) { + // If a component throws an error, we replay it again in a synchronously + // dispatched event, so that the debugger will treat it as an uncaught + // error See ReactErrorUtils for more information. + + // Before entering the begin phase, copy the work-in-progress onto a dummy + // fiber. If beginWork throws, we'll use this to reset the state. + var originalWorkInProgressCopy = assignFiberPropertiesInDEV( + dummyFiber, + unitOfWork + ); + try { + return beginWork$1(current$$1, unitOfWork, expirationTime); + } catch (originalError) { + if ( + originalError !== null && + typeof originalError === "object" && + typeof originalError.then === "function" + ) { + // Don't replay promises. Treat everything else like an error. + throw originalError; + } + + // Keep this code in sync with renderRoot; any changes here must have + // corresponding changes there. + resetContextDependences(); + resetHooks(); + + // Unwind the failed stack frame + unwindInterruptedWork(unitOfWork); + + // Restore the original properties of the fiber. + assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); + + if (enableProfilerTimer && unitOfWork.mode & ProfileMode) { + // Reset the profiler timer. + startProfilerTimer(unitOfWork); + } + + // Run beginWork again. + invokeGuardedCallback( + null, + beginWork$1, + null, + current$$1, + unitOfWork, + expirationTime + ); + + if (hasCaughtError()) { + var replayError = clearCaughtError(); + // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`. + // Rethrow this error instead of the original one. + throw replayError; + } else { + // This branch is reachable if the render phase is impure. + throw originalError; + } + } + }; +} else { + beginWork$$1 = beginWork$1; +} + +var didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInGetChildContext = false; +function warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber) { + { + if (fiber.tag === ClassComponent) { + switch (phase) { + case "getChildContext": + if (didWarnAboutUpdateInGetChildContext) { + return; + } + warningWithoutStack$1( + false, + "setState(...): Cannot call setState() inside getChildContext()" + ); + didWarnAboutUpdateInGetChildContext = true; + break; + case "render": + if (didWarnAboutUpdateInRender) { + return; + } + warningWithoutStack$1( + false, + "Cannot update during an existing state transition (such as " + + "within `render`). Render methods should be a pure function of " + + "props and state." + ); + didWarnAboutUpdateInRender = true; + break; + } + } + } +} + +function warnIfNotCurrentlyActingUpdatesInDEV(fiber) { + { + if ( + workPhase === NotWorking && + ReactShouldWarnActingUpdates.current === false + ) { + warningWithoutStack$1( + false, + "An update to %s inside a test was not wrapped in act(...).\n\n" + + "When testing, code that causes React state updates should be " + + "wrapped into act(...):\n\n" + + "act(() => {\n" + + " /* fire events that update state */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://fb.me/react-wrap-tests-with-act" + + "%s", + getComponentName(fiber.type), + getStackByFiberInDevAndProd(fiber) + ); + } + } +} + +var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; + +function computeThreadID(root, expirationTime) { + // Interaction threads are unique per root and expiration time. + return expirationTime * 1000 + root.interactionThreadID; +} + +function schedulePendingInteraction(root, expirationTime) { + // This is called when work is scheduled on a root. It sets up a pending + // interaction, which is completed once the work commits. + if (!enableSchedulerTracing) { + return; + } + + var interactions = tracing.__interactionsRef.current; + if (interactions.size > 0) { + var pendingInteractionMap = root.pendingInteractionMap; + var pendingInteractions = pendingInteractionMap.get(expirationTime); + if (pendingInteractions != null) { + interactions.forEach(function(interaction) { + if (!pendingInteractions.has(interaction)) { + // Update the pending async work count for previously unscheduled interaction. + interaction.__count++; + } + + pendingInteractions.add(interaction); + }); + } else { + pendingInteractionMap.set(expirationTime, new Set(interactions)); + + // Update the pending async work count for the current interactions. + interactions.forEach(function(interaction) { + interaction.__count++; + }); + } + + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + subscriber.onWorkScheduled(interactions, threadID); + } + } +} + +function startWorkOnPendingInteraction(root, expirationTime) { + // This is called when new work is started on a root. + if (!enableSchedulerTracing) { + return; + } + + // Determine which interactions this batch of work currently includes, So that + // we can accurately attribute time spent working on it, And so that cascading + // work triggered during the render phase will be associated with it. + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + if (scheduledExpirationTime >= expirationTime) { + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + } + }); + + // Store the current set of interactions on the FiberRoot for a few reasons: + // We can re-use it in hot functions like renderRoot() without having to + // recalculate it. We will also use it in commitWork() to pass to any Profiler + // onRender() hooks. This also provides DevTools with a way to access it when + // the onCommitRoot() hook is called. + root.memoizedInteractions = interactions; + + if (interactions.size > 0) { + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + try { + subscriber.onWorkStarted(interactions, threadID); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + } +} + +function finishPendingInteractions(root, committedExpirationTime) { + if (!enableSchedulerTracing) { + return; + } + + var earliestRemainingTimeAfterCommit = root.firstPendingTime; + + var subscriber = void 0; + + try { + subscriber = tracing.__subscriberRef.current; + if (subscriber !== null && root.memoizedInteractions.size > 0) { + var threadID = computeThreadID(root, committedExpirationTime); + subscriber.onWorkStopped(root.memoizedInteractions, threadID); + } + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } finally { + // Clear completed interactions from the pending Map. + // Unless the render was suspended or cascading work was scheduled, + // In which case– leave pending interactions until the subsequent render. + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + // Only decrement the pending interaction count if we're done. + // If there's still work at the current priority, + // That indicates that we are waiting for suspense data. + if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { + pendingInteractionMap.delete(scheduledExpirationTime); + + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + + if (subscriber !== null && interaction.__count === 0) { + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + }); + } + }); + } +} + +// This lets us hook into Fiber to debug what it's doing. +// See https://github.com/facebook/react/pull/8033. +// This is not part of the public API, not even for React DevTools. +// You may only inject a debugTool if you work on React Fiber itself. +var ReactFiberInstrumentation = { + debugTool: null +}; + +var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; + +// 0 is PROD, 1 is DEV. +// Might add PROFILE later. + +var didWarnAboutNestedUpdates = void 0; +var didWarnAboutFindNodeInStrictMode = void 0; + +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; +} + +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + + if (fiber.tag === ClassComponent) { + var Component = fiber.type; + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } + } + + return parentContext; +} + +function scheduleRootUpdate(current$$1, element, expirationTime, callback) { + { + if (phase === "render" && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; + warningWithoutStack$1( + false, + "Render methods should be a pure function of props and state; " + + "triggering nested component updates from render is not allowed. " + + "If necessary, trigger nested updates in componentDidUpdate.\n\n" + + "Check the render method of %s.", + getComponentName(current.type) || "Unknown" + ); + } + } + + var update = createUpdate(expirationTime); + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: element }; + + callback = callback === undefined ? null : callback; + if (callback !== null) { + !(typeof callback === "function") + ? warningWithoutStack$1( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(current$$1, update); + scheduleWork(current$$1, expirationTime); + + return expirationTime; +} + +function updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback +) { + // TODO: If this is a nested container, this won't be the root. + var current$$1 = container.current; + + { + if (ReactFiberInstrumentation_1.debugTool) { + if (current$$1.alternate === null) { + ReactFiberInstrumentation_1.debugTool.onMountContainer(container); + } else if (element === null) { + ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container); + } else { + ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container); + } + } + } + + var context = getContextForSubtree(parentComponent); + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } + + return scheduleRootUpdate(current$$1, element, expirationTime, callback); +} + +function findHostInstance(component) { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; +} + +function findHostInstanceWithWarning(component, methodName) { + { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + if (hostFiber.mode & StrictMode) { + var componentName = getComponentName(fiber.type) || "Component"; + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + if (fiber.mode & StrictMode) { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which is inside StrictMode. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } else { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which renders StrictMode children. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } + } + } + return hostFiber.stateNode; + } + return findHostInstance(component); +} + +function createContainer(containerInfo, isConcurrent, hydrate) { + return createFiberRoot(containerInfo, isConcurrent, hydrate); +} + +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current; + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, current$$1); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback + ); +} + +function getPublicRootInstance(container) { + var containerFiber = container.current; + if (!containerFiber.child) { + return null; + } + switch (containerFiber.child.tag) { + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); + default: + return containerFiber.child.stateNode; + } +} + +var shouldSuspendImpl = function(fiber) { + return false; +}; + +function shouldSuspend(fiber) { + return shouldSuspendImpl(fiber); +} + +var overrideHookState = null; +var overrideProps = null; +var scheduleUpdate = null; +var setSuspenseHandler = null; + +{ + var copyWithSetImpl = function(obj, path, idx, value) { + if (idx >= path.length) { + return value; + } + var key = path[idx]; + var updated = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj); + // $FlowFixMe number or string is fine here + updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value); + return updated; + }; + + var copyWithSet = function(obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; + + // Support DevTools editable values for useState and useReducer. + overrideHookState = function(fiber, id, path, value) { + // For now, the "id" of stateful hooks is just the stateful hook index. + // This may change in the future with e.g. nested hooks. + var currentHook = fiber.memoizedState; + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } + if (currentHook !== null) { + flushPassiveEffects(); + + var newState = copyWithSet(currentHook.memoizedState, path, value); + currentHook.memoizedState = newState; + currentHook.baseState = newState; + + // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. + fiber.memoizedProps = Object.assign({}, fiber.memoizedProps); + + scheduleWork(fiber, Sync); + } + }; + + // Support DevTools props for function components, forwardRef, memo, host components, etc. + overrideProps = function(fiber, path, value) { + flushPassiveEffects(); + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } + scheduleWork(fiber, Sync); + }; + + scheduleUpdate = function(fiber) { + flushPassiveEffects(); + scheduleWork(fiber, Sync); + }; + + setSuspenseHandler = function(newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; +} + +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; + + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: overrideHookState, + overrideProps: overrideProps, + setSuspenseHandler: setSuspenseHandler, + scheduleUpdate: scheduleUpdate, + currentDispatcherRef: ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + if (!findFiberByHostInstance) { + // Might not be implemented by the renderer. + return null; + } + return findFiberByHostInstance(instance); + } + }) + ); +} + +// This file intentionally does *not* have the Flow annotation. +// Don't add it. See `./inline-typed.js` for an explanation. + +function createPortal( + children, + containerInfo, + // TODO: figure out the API for cross-renderer implementation. + implementation +) { + var key = + arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + + return { + // This tag allow us to uniquely identify this as a React Portal + $$typeof: REACT_PORTAL_TYPE, + key: key == null ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} + +// TODO: this is special because it gets imported during build. + +var ReactVersion = "16.8.6"; + +// Modules provided by RN: +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { + /** + * `NativeMethodsMixin` provides methods to access the underlying native + * component directly. This can be useful in cases when you want to focus + * a view or measure its on-screen dimensions, for example. + * + * The methods described here are available on most of the default components + * provided by React Native. Note, however, that they are *not* available on + * composite components that aren't directly backed by a native view. This will + * generally include most components that you define in your own app. For more + * information, see [Direct + * Manipulation](docs/direct-manipulation.html). + * + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. + */ + var NativeMethodsMixin = { + /** + * Determines the location on screen, width, and height of the given view and + * returns the values via an async callback. If successful, the callback will + * be called with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * Note that these measurements are not available until after the rendering + * has been completed in native. If you need the measurements as soon as + * possible, consider using the [`onLayout` + * prop](docs/view.html#onlayout) instead. + */ + measure: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Like [`measure()`](#measure), but measures the view relative an ancestor, + * specified as `relativeToNativeNode`. This means that the returned x, y + * are relative to the origin x, y of the ancestor view. + * + * As always, to obtain a native node handle for a component, you can use + * `findNodeHandle(component)`. + */ + measureLayout: function( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }, + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + setNativeProps: function(nativeProps) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }, + + /** + * Requests focus for the given input or view. The exact behavior triggered + * will depend on the platform and type of view. + */ + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + + { + // hide this from Flow since we can't define these properties outside of + // true without actually implementing them (setting them to undefined + // isn't allowed by ReactClass) + var NativeMethodsMixin_DEV = NativeMethodsMixin; + (function() { + if ( + !( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps + ) + ) { + throw ReactError("Do not override existing functions."); + } + })(); + // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, + // Once these lifecycles have been remove from the reconciler. + NativeMethodsMixin_DEV.componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { + throwOnStylesProp(this, newProps); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function( + newProps + ) { + throwOnStylesProp(this, newProps); + }; + + // React may warn about cWM/cWRP/cWU methods being deprecated. + // Add a flag to suppress these warnings for this special case. + // TODO (bvaughn) Remove this flag once the above methods have been removed. + NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; + NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; + } + + return NativeMethodsMixin; +}; + +function _classCallCheck$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +function _possibleConstructorReturn(self, call) { + if (!self) { + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + } + return call && (typeof call === "object" || typeof call === "function") + ? call + : self; +} + +function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) + Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass); +} + +// Modules provided by RN: +var ReactNativeComponent = function(findNodeHandle, findHostInstance) { + /** + * Superclass that provides methods to access the underlying native component. + * This can be useful when you want to focus a view or measure its dimensions. + * + * Methods implemented by this class are available on most default components + * provided by React Native. However, they are *not* available on composite + * components that are not directly backed by a native view. For more + * information, see [Direct Manipulation](docs/direct-manipulation.html). + * + * @abstract + */ + var ReactNativeComponent = (function(_React$Component) { + _inherits(ReactNativeComponent, _React$Component); + + function ReactNativeComponent() { + _classCallCheck$1(this, ReactNativeComponent); + + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) + ); + } + + /** + * Removes focus. This is the opposite of `focus()`. + */ + + /** + * Due to bugs in Flow's handling of React.createClass, some fields already + * declared in the base class need to be redeclared below. + */ + ReactNativeComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + + /** + * Measures the on-screen location and dimensions. If successful, the callback + * will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * These values are not available until after natives rendering completes. If + * you need the measurements as soon as possible, consider using the + * [`onLayout` prop](docs/view.html#onlayout) instead. + */ + + ReactNativeComponent.prototype.measure = function measure(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Measures the on-screen location and dimensions. Even if the React Native + * root view is embedded within another native view, this method will give you + * the absolute coordinates measured from the window. If successful, the + * callback will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * + * These values are not available until after natives rendering completes. + */ + + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Similar to [`measure()`](#measure), but the resulting location will be + * relative to the supplied ancestor's location. + * + * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. + */ + + ReactNativeComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }; + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + + ReactNativeComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than ReactNative.findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions + + return ReactNativeComponent; +}; + +var instanceCache = {}; + +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} + +// Module provided by RN: +var emptyObject$1 = {}; +{ + Object.freeze(emptyObject$1); +} + +var getInspectorDataForViewTag = void 0; + +{ + var traverseOwnerTreeUp = function(hierarchy, instance) { + if (instance) { + hierarchy.unshift(instance); + traverseOwnerTreeUp(hierarchy, instance._debugOwner); + } + }; + + var getOwnerHierarchy = function(instance) { + var hierarchy = []; + traverseOwnerTreeUp(hierarchy, instance); + return hierarchy; + }; + + var lastNonHostInstance = function(hierarchy) { + for (var i = hierarchy.length - 1; i > 1; i--) { + var instance = hierarchy[i]; + + if (instance.tag !== HostComponent) { + return instance; + } + } + return hierarchy[0]; + }; + + var getHostProps = function(fiber) { + var host = findCurrentHostFiber(fiber); + if (host) { + return host.memoizedProps || emptyObject$1; + } + return emptyObject$1; + }; + + var getHostNode = function(fiber, findNodeHandle) { + var hostNode = void 0; + // look for children first for the hostNode + // as composite fibers do not have a hostNode + while (fiber) { + if (fiber.stateNode !== null && fiber.tag === HostComponent) { + hostNode = findNodeHandle(fiber.stateNode); + } + if (hostNode) { + return hostNode; + } + fiber = fiber.child; + } + return null; + }; + + var createHierarchy = function(fiberHierarchy) { + return fiberHierarchy.map(function(fiber) { + return { + name: getComponentName(fiber.type), + getInspectorData: function(findNodeHandle) { + return { + measure: function(callback) { + return ReactNativePrivateInterface.UIManager.measure( + getHostNode(fiber, findNodeHandle), + callback + ); + }, + props: getHostProps(fiber), + source: fiber._debugSource + }; + } + }; + }); + }; + + getInspectorDataForViewTag = function(viewTag) { + var closestInstance = getInstanceFromTag(viewTag); + + // Handle case where user clicks outside of ReactNative + if (!closestInstance) { + return { + hierarchy: [], + props: emptyObject$1, + selection: null, + source: null + }; + } + + var fiber = findCurrentFiberUsingSlowPath(closestInstance); + var fiberHierarchy = getOwnerHierarchy(fiber); + var instance = lastNonHostInstance(fiberHierarchy); + var hierarchy = createHierarchy(fiberHierarchy); + var props = getHostProps(instance); + var source = instance._debugSource; + var selection = fiberHierarchy.indexOf(instance); + + return { + hierarchy: hierarchy, + props: props, + selection: selection, + source: source + }; + }; +} + +var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; + +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing findNodeHandle inside its render(). " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(owner.type) || "A component" + ) + : void 0; + + owner.stateNode._warnedAboutRefsInRender = true; + } + } + if (componentOrHandle == null) { + return null; + } + if (typeof componentOrHandle === "number") { + // Already a node handle + return componentOrHandle; + } + if (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) { + return componentOrHandle.canonical._nativeTag; + } + var hostInstance = void 0; + { + hostInstance = findHostInstanceWithWarning( + componentOrHandle, + "findNodeHandle" + ); + } + + if (hostInstance == null) { + return hostInstance; + } + // TODO: the code is right but the types here are wrong. + // https://github.com/facebook/react/pull/12863 + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; +} + +setBatchingImplementation( + batchedUpdates$1, + interactiveUpdates$1, + flushInteractiveUpdates$1 +); + +var roots = new Map(); + +var ReactFabric = { + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), + + findNodeHandle: findNodeHandle, + + setNativeProps: function(handle, nativeProps) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + + return; + }, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + + if (!root) { + // TODO (bvaughn): If we decide to keep the wrapper component, + // We could create a wrapper for containerTag as well to reduce special casing. + root = createContainer(containerTag, false, false); + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + + return getPublicRootInstance(root); + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + if (root) { + // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + } + }, + createPortal: function(children, containerTag) { + var key = + arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + return createPortal(children, containerTag, null, key); + }, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + // Used as a mixin in many createClass-based components + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance) + } +}; + +injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 1, + version: ReactVersion, + rendererPackageName: "react-native-renderer" +}); + +var ReactFabric$2 = Object.freeze({ + default: ReactFabric +}); + +var ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var fabric = ReactFabric$3.default || ReactFabric$3; + +module.exports = fabric; + + })(); +} diff --git a/Libraries/Renderer/oss/ReactFabric-dev.js b/Libraries/Renderer/implementations/ReactFabric-dev.js similarity index 99% rename from Libraries/Renderer/oss/ReactFabric-dev.js rename to Libraries/Renderer/implementations/ReactFabric-dev.js index 5ea69a29fba41a..f1676471c4da4e 100644 --- a/Libraries/Renderer/oss/ReactFabric-dev.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.js @@ -16,19 +16,12 @@ if (__DEV__) { (function() { "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); -var UIManager = require("UIManager"); +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); var React = require("react"); -var deepDiffer = require("deepDiffer"); -var flattenStyle = require("flattenStyle"); -var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); -var TextInputState = require("TextInputState"); -var FabricUIManager = require("FabricUIManager"); var checkPropTypes = require("prop-types/checkPropTypes"); var Scheduler = require("scheduler"); var tracing = require("scheduler/tracing"); -var ExceptionsManager = require("ExceptionsManager"); // Do not require this module directly! Use a normal error constructor with // template literal strings. The messages will be converted to ReactError during @@ -1561,7 +1554,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get$$1 + get: get }; function set(val) { @@ -1570,7 +1563,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get$$1() { + function get() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1913,7 +1906,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes$1 = { +var eventTypes = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -2204,12 +2197,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : topLevelType === TOP_SELECTION_CHANGE - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -2243,7 +2236,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2254,7 +2247,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -2271,7 +2264,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -2282,7 +2275,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2351,7 +2344,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2401,11 +2394,11 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes$1.responderStart + ? eventTypes.responderStart : isResponderTouchMove - ? eventTypes$1.responderMove + ? eventTypes.responderMove : isResponderTouchEnd - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null; if (incrementalTouch) { @@ -2428,9 +2421,9 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : isResponderRelease - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( @@ -2462,8 +2455,18 @@ var ResponderEventPlugin = { } }; +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + var ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: eventTypes$1, /** * @see {EventPluginHub.extractEvents} @@ -2478,10 +2481,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType]; - var directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; (function() { if (!(bubbleDispatchConfig || directDispatchConfig)) { throw ReactError( @@ -2555,9 +2556,12 @@ var ReactFabricGlobalResponderHandler = { onChange: function(from, to, blockNativeResponder) { if (to !== null) { var tag = to.stateNode.canonical._nativeTag; - UIManager.setJSResponder(tag, blockNativeResponder); + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); } else { - UIManager.clearJSResponder(); + ReactNativePrivateInterface.UIManager.clearJSResponder(); } } }; @@ -2588,7 +2592,7 @@ ResponderEventPlugin.injection.injectGlobalResponderHandler( * supported we can rename it. */ -function get$1(key) { +function get(key) { return key._reactInternalFiber; } @@ -2855,7 +2859,7 @@ function isMounted(component) { } } - var fiber = get$1(component); + var fiber = get(component); if (!fiber) { return false; } @@ -3145,7 +3149,7 @@ function defaultDiffer(prevProp, nextProp) { return true; } else { // For objects and arrays, the default diffing algorithm is a deep compare - return deepDiffer(prevProp, nextProp); + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); } } @@ -3285,7 +3289,7 @@ function diffNestedProperty( return diffProperties( updatePayload, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. nextProp, validAttributes @@ -3296,7 +3300,7 @@ function diffNestedProperty( updatePayload, prevProp, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -3680,7 +3684,7 @@ function shim() { // Mutation (when unsupported) var supportsMutation = false; -var appendChild$1 = shim; +var appendChild = shim; var appendChildToContainer = shim; var commitTextUpdate = shim; var commitMount = shim; @@ -3742,18 +3746,37 @@ function _classCallCheck(instance, Constructor) { } // Modules provided by RN: +var _nativeFabricUIManage = nativeFabricUIManager; +var createNode = _nativeFabricUIManage.createNode; +var cloneNode = _nativeFabricUIManage.cloneNode; +var cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren; +var cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps; +var cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps; +var createChildNodeSet = _nativeFabricUIManage.createChildSet; +var appendChildNode = _nativeFabricUIManage.appendChild; +var appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet; +var completeRoot = _nativeFabricUIManage.completeRoot; +var registerEventHandler = _nativeFabricUIManage.registerEventHandler; +var fabricMeasure = _nativeFabricUIManage.measure; +var fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow; +var fabricMeasureLayout = _nativeFabricUIManage.measureLayout; +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; + // Counter for uniquely identifying views. // % 10 === 1 means it is a rootTag. // % 2 === 0 means it is a Fabric tag. // This means that they never overlap. + var nextReactTag = 2; // TODO: Remove this conditional once all changes have propagated. -if (FabricUIManager.registerEventHandler) { +if (registerEventHandler) { /** * Register the event emitter with the native bridge */ - FabricUIManager.registerEventHandler(dispatchEvent); + registerEventHandler(dispatchEvent); } /** @@ -3776,30 +3799,30 @@ var ReactFabricHostComponent = (function() { } ReactFabricHostComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; - ReactFabricHostComponent.prototype.measure = function measure$$1(callback) { - FabricUIManager.measure( + ReactFabricHostComponent.prototype.measure = function measure(callback) { + fabricMeasure( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; - ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow$$1( + ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow( callback ) { - FabricUIManager.measureInWindow( + fabricMeasureInWindow( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; - ReactFabricHostComponent.prototype.measureLayout = function measureLayout$$1( + ReactFabricHostComponent.prototype.measureLayout = function measureLayout( relativeToNativeNode, onSuccess, onFail /* currently unused */ @@ -3816,7 +3839,7 @@ var ReactFabricHostComponent = (function() { return; } - FabricUIManager.measureLayout( + fabricMeasureLayout( this._internalInstanceHandle.stateNode.node, relativeToNativeNode._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -3839,7 +3862,7 @@ var ReactFabricHostComponent = (function() { })(); function appendInitialChild(parentInstance, child) { - FabricUIManager.appendChild(parentInstance.node, child.node); + appendChildNode(parentInstance.node, child.node); } function createInstance( @@ -3852,19 +3875,21 @@ function createInstance( var tag = nextReactTag; nextReactTag += 2; - var viewConfig = ReactNativeViewConfigRegistry.get(type); + var viewConfig = getViewConfigForType(type); { for (var key in viewConfig.validAttributes) { if (props.hasOwnProperty(key)) { - deepFreezeAndThrowOnMutationInDev(props[key]); + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); } } } var updatePayload = create(props, viewConfig.validAttributes); - var node = FabricUIManager.createNode( + var node = createNode( tag, // reactTag viewConfig.uiViewClassName, // viewName rootContainerInstance, // rootTag @@ -3902,7 +3927,7 @@ function createTextInstance( var tag = nextReactTag; nextReactTag += 2; - var node = FabricUIManager.createNode( + var node = createNode( tag, // reactTag "RCTRawText", // viewName rootContainerInstance, // rootTag @@ -4025,18 +4050,15 @@ function cloneInstance( var clone = void 0; if (keepChildren) { if (updatePayload !== null) { - clone = FabricUIManager.cloneNodeWithNewProps(node, updatePayload); + clone = cloneNodeWithNewProps(node, updatePayload); } else { - clone = FabricUIManager.cloneNode(node); + clone = cloneNode(node); } } else { if (updatePayload !== null) { - clone = FabricUIManager.cloneNodeWithNewChildrenAndProps( - node, - updatePayload - ); + clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); } else { - clone = FabricUIManager.cloneNodeWithNewChildren(node); + clone = cloneNodeWithNewChildren(node); } } return { @@ -4053,7 +4075,7 @@ function cloneHiddenInstance(instance, type, props, internalInstanceHandle) { viewConfig.validAttributes ); return { - node: FabricUIManager.cloneNodeWithNewProps(node, updatePayload), + node: cloneNodeWithNewProps(node, updatePayload), canonical: instance.canonical }; } @@ -4063,15 +4085,15 @@ function cloneHiddenTextInstance(instance, text, internalInstanceHandle) { } function createContainerChildSet(container) { - return FabricUIManager.createChildSet(container); + return createChildNodeSet(container); } function appendChildToContainerChildSet(childSet, child) { - FabricUIManager.appendChildToSet(childSet, child.node); + appendChildNodeToSet(childSet, child.node); } function finalizeContainerChildren(container, newChildren) { - FabricUIManager.completeRoot(container, newChildren); + completeRoot(container, newChildren); } function mountEventComponent(eventComponentInstance) { @@ -7565,7 +7587,7 @@ function applyDerivedStateFromProps( var classComponentUpdater = { isMounted: isMounted, enqueueSetState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7583,7 +7605,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7603,7 +7625,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(inst, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -14897,7 +14919,10 @@ function showErrorDialog(capturedError) { errorToHandle = new Error("Unspecified error at:" + componentStack); } - ExceptionsManager.handleException(errorToHandle, false); + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); // Return false here to prevent ReactFiberErrorLogger default behavior of // logging error details to console.error. Calls to console.error are @@ -15879,7 +15904,7 @@ function commitPlacement(finishedWork) { if (isContainer) { appendChildToContainer(parent, stateNode); } else { - appendChild$1(parent, stateNode); + appendChild(parent, stateNode); } } } else if (node.tag === HostPortal) { @@ -18559,7 +18584,7 @@ function getContextForSubtree(parentComponent) { return emptyContextObject; } - var fiber = get$1(parentComponent); + var fiber = get(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); if (fiber.tag === ClassComponent) { @@ -18645,7 +18670,7 @@ function updateContainerAtExpirationTime( } function findHostInstance(component) { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -18673,7 +18698,7 @@ function findHostInstance(component) { function findHostInstanceWithWarning(component, methodName) { { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -18958,7 +18983,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19006,7 +19031,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19069,7 +19094,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19141,7 +19166,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19154,14 +19179,18 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { * will depend on the platform and type of view. */ focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, /** * Removes focus from an input or view. This is the opposite of `focus()`. */ blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; @@ -19281,7 +19310,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * declared in the base class need to be redeclared below. */ ReactNativeComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; /** @@ -19289,7 +19320,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { */ ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; /** @@ -19308,7 +19341,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * [`onLayout` prop](docs/view.html#onlayout) instead. */ - ReactNativeComponent.prototype.measure = function measure$$1(callback) { + ReactNativeComponent.prototype.measure = function measure(callback) { var maybeInstance = void 0; // Fiber errors if findNodeHandle is called for an umounted component. @@ -19334,7 +19367,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19355,7 +19388,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * These values are not available until after natives rendering completes. */ - ReactNativeComponent.prototype.measureInWindow = function measureInWindow$$1( + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( callback ) { var maybeInstance = void 0; @@ -19383,7 +19416,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19397,7 +19430,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. */ - ReactNativeComponent.prototype.measureLayout = function measureLayout$$1( + ReactNativeComponent.prototype.measureLayout = function measureLayout( relativeToNativeNode, onSuccess, onFail /* currently unused */ @@ -19445,7 +19478,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19516,7 +19549,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19602,7 +19635,7 @@ var getInspectorDataForViewTag = void 0; getInspectorData: function(findNodeHandle) { return { measure: function(callback) { - return UIManager.measure( + return ReactNativePrivateInterface.UIManager.measure( getHostNode(fiber, findNodeHandle), callback ); diff --git a/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js new file mode 100644 index 00000000000000..414151d1168e47 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -0,0 +1,6974 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +function getInstanceFromInstance(instanceHandle) { + return instanceHandle; +} +getFiberCurrentPropsFromNode = function(inst) { + return inst.canonical.currentProps; +}; +getInstanceFromNode = getInstanceFromInstance; +getNodeFromInstance = function(inst) { + inst = inst.stateNode.canonical._nativeTag; + if (!inst) throw ReactError("All native instances should have a tag."); + return inst; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode.canonical._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +function dispatchEvent(target, topLevelType, nativeEvent) { + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + target, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); +var ReactFabricHostComponent = (function() { + function ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ) { + if (!(this instanceof ReactFabricHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + this._internalInstanceHandle = internalInstanceHandle; + } + ReactFabricHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.measure = function(callback) { + fabricMeasure( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureInWindow = function(callback) { + fabricMeasureInWindow( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + "number" !== typeof relativeToNativeNode && + relativeToNativeNode instanceof ReactFabricHostComponent && + fabricMeasureLayout( + this._internalInstanceHandle.stateNode.node, + relativeToNativeNode._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactFabricHostComponent.prototype.setNativeProps = function() {}; + return ReactFabricHostComponent; +})(); +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + if (!hostContext.isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + hostContext = nextReactTag; + nextReactTag += 2; + return { + node: createNode( + hostContext, + "RCTRawText", + rootContainerInstance, + { text: text }, + internalInstanceHandle + ) + }; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout; +function cloneHiddenInstance(instance) { + var node = instance.node; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + instance.canonical.viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, updatePayload), + canonical: instance.canonical + }; +} +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority, + fakeCallbackNode = {}, + shouldYield = Scheduler.unstable_shouldYield, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue2, providerFiber); + context._currentValue2 = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue2 = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue2; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = + didCaptureError && "function" !== typeof Component.getDerivedStateFromError + ? null + : shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + mode = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = mode; + renderExpirationTime = current$$1; + renderExpirationTime.return = mode.return = workInProgress; + } else + renderExpirationTime = mode = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else + null !== current$$1.memoizedState + ? ((mode = current$$1.child), + (nextFallbackChildren = mode.sibling), + nextDidTimeout + ? ((renderExpirationTime = nextProps.fallback), + (nextProps = createWorkInProgress(mode, mode.pendingProps, 0)), + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== mode.child && + (nextProps.child = nextDidTimeout)), + (mode = nextProps.sibling = createWorkInProgress( + nextFallbackChildren, + renderExpirationTime, + nextFallbackChildren.expirationTime + )), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + mode.child, + nextProps.children, + renderExpirationTime + ))) + : ((nextFallbackChildren = current$$1.child), + nextDidTimeout + ? ((nextDidTimeout = nextProps.fallback), + (nextProps = createFiberFromFragment(null, mode, 0, null)), + (nextProps.child = nextFallbackChildren), + 0 === (workInProgress.mode & 1) && + (nextProps.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + (mode = nextProps.sibling = createFiberFromFragment( + nextDidTimeout, + mode, + renderExpirationTime, + null + )), + (mode.effectTag |= 2), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren, + nextProps.children, + renderExpirationTime + ))), + (workInProgress.stateNode = current$$1.stateNode); + workInProgress.memoizedState = nextState; + workInProgress.child = renderExpirationTime; + return mode; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNode(parent.node, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNode(parent.node, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildren(parent, primaryChildParent, !0, instance)), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +function appendAllChildrenToContainer( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + !0, + instance + )), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + if (null !== workInProgress.firstEffect) { + var container = portalOrRoot.containerInfo, + newChildSet = createChildNodeSet(container); + appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); + portalOrRoot.pendingChildren = newChildSet; + workInProgress.effectTag |= 4; + completeRoot(container, newChildSet); + } +}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + type = current.stateNode; + var oldProps = current.memoizedProps; + if ((current = null === workInProgress.firstEffect) && oldProps === newProps) + workInProgress.stateNode = type; + else { + var recyclableInstance = workInProgress.stateNode; + requiredContext(contextStackCursor$1.current); + var updatePayload = null; + oldProps !== newProps && + ((oldProps = diffProperties( + null, + oldProps, + newProps, + recyclableInstance.canonical.viewConfig.validAttributes + )), + (recyclableInstance.canonical.currentProps = newProps), + (updatePayload = oldProps)); + current && null === updatePayload + ? (workInProgress.stateNode = type) + : ((newProps = updatePayload), + (recyclableInstance = type.node), + (type = { + node: current + ? null !== newProps + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) + : null !== newProps + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), + canonical: type.canonical + }), + (workInProgress.stateNode = type), + current + ? (workInProgress.effectTag |= 4) + : appendAllChildren(type, workInProgress, !1, !1)); + } +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && + ((current = requiredContext(rootInstanceStackCursor.current)), + (oldText = requiredContext(contextStackCursor$1.current)), + (workInProgress.stateNode = createTextInstance( + newText, + current, + oldText, + workInProgress + )), + (workInProgress.effectTag |= 4)); +}; +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + case 12: + return; + case 13: + commitSuspenseComponent(finishedWork); + return; + } + switch (finishedWork.tag) { + case 1: + case 5: + case 6: + case 20: + case 19: + break; + case 3: + case 4: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + null !== newState && + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + (retryCache.add(thenable), thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + (root$jscomp$0 === workInProgressRoot && + expirationTime === renderExpirationTime) || + prepareFreshStack(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var next = beginWork$$1( + unitOfWork.alternate, + unitOfWork, + renderExpirationTime + ); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === next && (next = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return next; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + a: { + var current = current$$1; + current$$1 = workInProgress; + var renderExpirationTime$jscomp$0 = renderExpirationTime, + newProps = current$$1.pendingProps; + switch (current$$1.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 3: + popHostContainer(current$$1); + popTopLevelContextObject(current$$1); + newProps = current$$1.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + current$$1.effectTag &= -3; + updateHostContainer(current$$1); + break; + case 5: + popHostContext(current$$1); + renderExpirationTime$jscomp$0 = requiredContext( + rootInstanceStackCursor.current + ); + var type = current$$1.type; + if (null !== current && null != current$$1.stateNode) + updateHostComponent$1( + current, + current$$1, + type, + newProps, + renderExpirationTime$jscomp$0 + ), + current.ref !== current$$1.ref && (current$$1.effectTag |= 128); + else if (newProps) { + requiredContext(contextStackCursor$1.current); + current = newProps; + var rootContainerInstance = renderExpirationTime$jscomp$0; + newProps = current$$1; + renderExpirationTime$jscomp$0 = nextReactTag; + nextReactTag += 2; + type = getViewConfigForType(type); + var updatePayload = diffProperties( + null, + emptyObject, + current, + type.validAttributes + ); + rootContainerInstance = createNode( + renderExpirationTime$jscomp$0, + type.uiViewClassName, + rootContainerInstance, + updatePayload, + newProps + ); + current = new ReactFabricHostComponent( + renderExpirationTime$jscomp$0, + type, + current, + newProps + ); + current = { node: rootContainerInstance, canonical: current }; + appendAllChildren(current, current$$1, !1, !1); + current$$1.stateNode = current; + null !== current$$1.ref && (current$$1.effectTag |= 128); + } else if (null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != current$$1.stateNode) + updateHostText$1( + current, + current$$1, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + renderExpirationTime$jscomp$0 = requiredContext( + contextStackCursor$1.current + ); + current$$1.stateNode = createTextInstance( + newProps, + current, + renderExpirationTime$jscomp$0, + current$$1 + ); + } + break; + case 11: + break; + case 13: + newProps = current$$1.memoizedState; + if (0 !== (current$$1.effectTag & 64)) { + current$$1.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + newProps = null !== newProps; + renderExpirationTime$jscomp$0 = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime$jscomp$0 = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (current = current.child.sibling), + null !== current && + ((type = current$$1.firstEffect), + null !== type + ? ((current$$1.firstEffect = current), + (current.nextEffect = type)) + : ((current$$1.firstEffect = current$$1.lastEffect = current), + (current.nextEffect = null)), + (current.effectTag = 8)))); + newProps && + !renderExpirationTime$jscomp$0 && + 0 !== (current$$1.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + newProps && (current$$1.effectTag |= 4); + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(current$$1); + updateHostContainer(current$$1); + break; + case 10: + popProvider(current$$1); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + current$$1 = null; + } + current = workInProgress; + if (1 === renderExpirationTime || 1 !== current.childExpirationTime) { + newProps = 0; + for ( + renderExpirationTime$jscomp$0 = current.child; + null !== renderExpirationTime$jscomp$0; + + ) + (type = renderExpirationTime$jscomp$0.expirationTime), + (rootContainerInstance = + renderExpirationTime$jscomp$0.childExpirationTime), + type > newProps && (newProps = type), + rootContainerInstance > newProps && + (newProps = rootContainerInstance), + (renderExpirationTime$jscomp$0 = + renderExpirationTime$jscomp$0.sibling); + current.childExpirationTime = newProps; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + 1 < finishedWork.effectTag + ? null !== finishedWork.lastEffect + ? ((finishedWork.lastEffect.nextEffect = finishedWork), + (childExpirationTimeBeforeCommit = finishedWork.firstEffect)) + : (childExpirationTimeBeforeCommit = finishedWork) + : (childExpirationTimeBeforeCommit = finishedWork.firstEffect); + if (null !== childExpirationTimeBeforeCommit) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + ReactCurrentOwner$2.current = null; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + nextEffect.effectTag &= -3; + break; + case 6: + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + a: for (prevState = prevProps = current$$1; ; ) { + instance = prevState; + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(instance); + switch (instance.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = instance.updateQueue; + if (null !== updateQueue) { + var lastEffect = updateQueue.lastEffect; + if (null !== lastEffect) { + var firstEffect = lastEffect.next; + snapshot = firstEffect; + do { + var destroy = snapshot.destroy; + if (void 0 !== destroy) { + finishedWork$jscomp$0 = instance; + try { + destroy(); + } catch (error) { + captureCommitPhaseError( + finishedWork$jscomp$0, + error + ); + } + } + snapshot = snapshot.next; + } while (snapshot !== firstEffect); + } + } + break; + case 1: + safelyDetachRef(instance); + var instance$jscomp$0 = instance.stateNode; + if ( + "function" === + typeof instance$jscomp$0.componentWillUnmount + ) + try { + (instance$jscomp$0.props = instance.memoizedProps), + (instance$jscomp$0.state = instance.memoizedState), + instance$jscomp$0.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(instance, unmountError); + } + break; + case 5: + safelyDetachRef(instance); + break; + case 4: + createChildNodeSet(instance.stateNode.containerInfo); + } + if (null !== prevState.child) + (prevState.child.return = prevState), + (prevState = prevState.child); + else { + if (prevState === prevProps) break; + for (; null === prevState.sibling; ) { + if ( + null === prevState.return || + prevState.return === prevProps + ) + break a; + prevState = prevState.return; + } + prevState.sibling.return = prevState.return; + prevState = prevState.sibling; + } + } + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (effectTag = expirationTime; null !== nextEffect; ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + var current$$1$jscomp$1 = nextEffect.alternate; + current$$1$jscomp$0 = nextEffect; + currentRef = effectTag; + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountLayout, + MountLayout, + current$$1$jscomp$0 + ); + break; + case 1: + var instance$jscomp$1 = current$$1$jscomp$0.stateNode; + if (current$$1$jscomp$0.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$1.componentDidMount(); + else { + var prevProps$jscomp$0 = + current$$1$jscomp$0.elementType === + current$$1$jscomp$0.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + current$$1$jscomp$0.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$1.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$1.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue$jscomp$0 = current$$1$jscomp$0.updateQueue; + null !== updateQueue$jscomp$0 && + commitUpdateQueue( + current$$1$jscomp$0, + updateQueue$jscomp$0, + instance$jscomp$1, + currentRef + ); + break; + case 3: + var _updateQueue = current$$1$jscomp$0.updateQueue; + if (null !== _updateQueue) { + updateQueue = null; + if (null !== current$$1$jscomp$0.child) + switch (current$$1$jscomp$0.child.tag) { + case 5: + updateQueue = + current$$1$jscomp$0.child.stateNode.canonical; + break; + case 1: + updateQueue = current$$1$jscomp$0.child.stateNode; + } + commitUpdateQueue( + current$$1$jscomp$0, + _updateQueue, + updateQueue, + currentRef + ); + } + break; + case 5: + if ( + null === current$$1$jscomp$1 && + current$$1$jscomp$0.effectTag & 4 + ) + throw ReactError( + "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + break; + case 4: + break; + case 12: + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$2 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$2.canonical; + break; + default: + instanceToUse = instance$jscomp$2; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + workPhase = updateExpirationTimeBeforeCommit; + } else root.current = finishedWork; + rootDoesHavePassiveEffects && + ((rootDoesHavePassiveEffects = !1), (rootWithPendingPassiveEffects = root)); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects; + rootWithPendingPassiveEffects = null; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (root = root.current.firstEffect; null !== root; ) { + try { + var finishedWork = root; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === root) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(root, error); + } + root = root.nextEffect; + } + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactFabric = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function() {}, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = createFiber(3, null, null, 0); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode.canonical; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance) + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactFabric$2 = { default: ReactFabric }, + ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; +module.exports = ReactFabric$3.default || ReactFabric$3; diff --git a/Libraries/Renderer/oss/ReactFabric-prod.js b/Libraries/Renderer/implementations/ReactFabric-prod.js similarity index 97% rename from Libraries/Renderer/oss/ReactFabric-prod.js rename to Libraries/Renderer/implementations/ReactFabric-prod.js index afbbd4ce6b1b9f..50abb2ccc511cd 100644 --- a/Libraries/Renderer/oss/ReactFabric-prod.js +++ b/Libraries/Renderer/implementations/ReactFabric-prod.js @@ -11,16 +11,10 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), - FabricUIManager = require("FabricUIManager"), Scheduler = require("scheduler"); -var ExceptionsManager = require("ExceptionsManager"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -617,7 +611,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -680,7 +674,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -709,12 +703,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -800,7 +794,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -810,7 +804,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -822,7 +816,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -836,7 +830,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -866,11 +860,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -924,9 +918,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -948,8 +942,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -957,10 +958,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1002,11 +1001,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder( + ? ReactNativePrivateInterface.UIManager.setJSResponder( to.stateNode.canonical._nativeTag, blockNativeResponder ) - : UIManager.clearJSResponder(); + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1279,14 +1278,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1354,7 +1353,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1366,7 +1365,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1483,9 +1482,25 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var nextReactTag = 2; -FabricUIManager.registerEventHandler && - FabricUIManager.registerEventHandler(dispatchEvent); +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); var ReactFabricHostComponent = (function() { function ReactFabricHostComponent( tag, @@ -1501,19 +1516,19 @@ var ReactFabricHostComponent = (function() { this._internalInstanceHandle = internalInstanceHandle; } ReactFabricHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.measure = function(callback) { - FabricUIManager.measure( + fabricMeasure( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactFabricHostComponent.prototype.measureInWindow = function(callback) { - FabricUIManager.measureInWindow( + fabricMeasureInWindow( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1525,7 +1540,7 @@ var ReactFabricHostComponent = (function() { ) { "number" !== typeof relativeToNativeNode && relativeToNativeNode instanceof ReactFabricHostComponent && - FabricUIManager.measureLayout( + fabricMeasureLayout( this._internalInstanceHandle.stateNode.node, relativeToNativeNode._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1548,7 +1563,7 @@ function createTextInstance( hostContext = nextReactTag; nextReactTag += 2; return { - node: FabricUIManager.createNode( + node: createNode( hostContext, "RCTRawText", rootContainerInstance, @@ -1568,7 +1583,7 @@ function cloneHiddenInstance(instance) { instance.canonical.viewConfig.validAttributes ); return { - node: FabricUIManager.cloneNodeWithNewProps(node, updatePayload), + node: cloneNodeWithNewProps(node, updatePayload), canonical: instance.canonical }; } @@ -4457,12 +4472,12 @@ appendAllChildren = function( node.memoizedProps, node )); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4515,12 +4530,12 @@ function appendAllChildrenToContainer( node.memoizedProps, node )); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4565,11 +4580,11 @@ updateHostContainer = function(workInProgress) { var portalOrRoot = workInProgress.stateNode; if (null !== workInProgress.firstEffect) { var container = portalOrRoot.containerInfo, - newChildSet = FabricUIManager.createChildSet(container); + newChildSet = createChildNodeSet(container); appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); portalOrRoot.pendingChildren = newChildSet; workInProgress.effectTag |= 4; - FabricUIManager.completeRoot(container, newChildSet); + completeRoot(container, newChildSet); } }; updateHostComponent$1 = function(current, workInProgress, type, newProps) { @@ -4597,17 +4612,11 @@ updateHostComponent$1 = function(current, workInProgress, type, newProps) { (type = { node: current ? null !== newProps - ? FabricUIManager.cloneNodeWithNewProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNode(recyclableInstance) + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) : null !== newProps - ? FabricUIManager.cloneNodeWithNewChildrenAndProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNodeWithNewChildren(recyclableInstance), + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), canonical: type.canonical }), (workInProgress.stateNode = type), @@ -4652,7 +4661,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -5383,14 +5392,14 @@ function completeUnitOfWork(unitOfWork) { newProps = current$$1; renderExpirationTime$jscomp$0 = nextReactTag; nextReactTag += 2; - type = ReactNativeViewConfigRegistry.get(type); + type = getViewConfigForType(type); var updatePayload = diffProperties( null, emptyObject, current, type.validAttributes ); - rootContainerInstance = FabricUIManager.createNode( + rootContainerInstance = createNode( renderExpirationTime$jscomp$0, type.uiViewClassName, rootContainerInstance, @@ -5732,9 +5741,7 @@ function commitRootImpl(root, expirationTime) { safelyDetachRef(instance); break; case 4: - FabricUIManager.createChildSet( - instance.stateNode.containerInfo - ); + createChildNodeSet(instance.stateNode.containerInfo); } if (null !== prevState.child) (prevState.child.return = prevState), @@ -6712,10 +6719,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -6728,7 +6739,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6744,7 +6755,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6766,7 +6777,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -6790,7 +6801,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -6852,7 +6863,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6868,7 +6879,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6886,7 +6897,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -6910,7 +6921,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -6918,10 +6929,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance) diff --git a/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js new file mode 100644 index 00000000000000..722fac68035257 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -0,0 +1,7211 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"), + tracing = require("scheduler/tracing"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +function getInstanceFromInstance(instanceHandle) { + return instanceHandle; +} +getFiberCurrentPropsFromNode = function(inst) { + return inst.canonical.currentProps; +}; +getInstanceFromNode = getInstanceFromInstance; +getNodeFromInstance = function(inst) { + inst = inst.stateNode.canonical._nativeTag; + if (!inst) throw ReactError("All native instances should have a tag."); + return inst; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode.canonical._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +function dispatchEvent(target, topLevelType, nativeEvent) { + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + target, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); +var ReactFabricHostComponent = (function() { + function ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ) { + if (!(this instanceof ReactFabricHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + this._internalInstanceHandle = internalInstanceHandle; + } + ReactFabricHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.measure = function(callback) { + fabricMeasure( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureInWindow = function(callback) { + fabricMeasureInWindow( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + "number" !== typeof relativeToNativeNode && + relativeToNativeNode instanceof ReactFabricHostComponent && + fabricMeasureLayout( + this._internalInstanceHandle.stateNode.node, + relativeToNativeNode._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactFabricHostComponent.prototype.setNativeProps = function() {}; + return ReactFabricHostComponent; +})(); +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + if (!hostContext.isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + hostContext = nextReactTag; + nextReactTag += 2; + return { + node: createNode( + hostContext, + "RCTRawText", + rootContainerInstance, + { text: text }, + internalInstanceHandle + ) + }; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout; +function cloneHiddenInstance(instance) { + var node = instance.node; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + instance.canonical.viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, updatePayload), + canonical: instance.canonical + }; +} +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +var isDevToolsPresent = "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__; +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_shouldYield = Scheduler.unstable_shouldYield, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; +if ( + null == tracing.__interactionsRef || + null == tracing.__interactionsRef.current +) + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); +var fakeCallbackNode = {}, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; + this.actualDuration = 0; + this.actualStartTime = -1; + this.treeBaseDuration = this.selfBaseDuration = 0; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null), + (workInProgress.actualDuration = 0), + (workInProgress.actualStartTime = -1)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue2, providerFiber); + context._currentValue2 = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue2 = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue2; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + now$1 = Scheduler.unstable_now, + commitTime = 0, + profilerStartTime = -1; +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (0 <= profilerStartTime) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + overrideBaseTime && (fiber.selfBaseDuration = elapsedTime); + profilerStartTime = -1; + } +} +var hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + if ( + didCaptureError && + "function" !== typeof Component.getDerivedStateFromError + ) { + var nextChildren = null; + profilerStartTime = -1; + } else nextChildren = shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((didCaptureError = nextChildren), + (workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + didCaptureError, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + renderExpirationTime = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = renderExpirationTime; + mode = current$$1; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else { + if (null !== current$$1.memoizedState) + if ( + ((nextFallbackChildren = current$$1.child), + (mode = nextFallbackChildren.sibling), + nextDidTimeout) + ) { + nextProps = nextProps.fallback; + renderExpirationTime = createWorkInProgress( + nextFallbackChildren, + nextFallbackChildren.pendingProps, + 0 + ); + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== nextFallbackChildren.child && + (renderExpirationTime.child = nextDidTimeout)); + if (workInProgress.mode & 4) { + nextFallbackChildren = 0; + for ( + nextDidTimeout = renderExpirationTime.child; + null !== nextDidTimeout; + + ) + (nextFallbackChildren += nextDidTimeout.treeBaseDuration), + (nextDidTimeout = nextDidTimeout.sibling); + renderExpirationTime.treeBaseDuration = nextFallbackChildren; + } + nextFallbackChildren = renderExpirationTime.sibling = createWorkInProgress( + mode, + nextProps, + mode.expirationTime + ); + mode = renderExpirationTime; + renderExpirationTime.childExpirationTime = 0; + renderExpirationTime = nextFallbackChildren; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren.child, + nextProps.children, + renderExpirationTime + ); + else { + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + nextProps = nextProps.fallback; + nextFallbackChildren = createFiberFromFragment(null, mode, 0, null); + nextFallbackChildren.child = _currentPrimaryChild; + 0 === (workInProgress.mode & 1) && + (nextFallbackChildren.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + if (workInProgress.mode & 4) { + nextDidTimeout = 0; + for ( + _currentPrimaryChild = nextFallbackChildren.child; + null !== _currentPrimaryChild; + + ) + (nextDidTimeout += _currentPrimaryChild.treeBaseDuration), + (_currentPrimaryChild = _currentPrimaryChild.sibling); + nextFallbackChildren.treeBaseDuration = nextDidTimeout; + } + renderExpirationTime = nextFallbackChildren.sibling = createFiberFromFragment( + nextProps, + mode, + renderExpirationTime, + null + ); + renderExpirationTime.effectTag |= 2; + mode = nextFallbackChildren; + nextFallbackChildren.childExpirationTime = 0; + mode.return = renderExpirationTime.return = workInProgress; + } else + renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + nextProps.children, + renderExpirationTime + ); + } + workInProgress.stateNode = current$$1.stateNode; + } + workInProgress.memoizedState = nextState; + workInProgress.child = mode; + return renderExpirationTime; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + profilerStartTime = -1; + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNode(parent.node, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNode(parent.node, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildren(parent, primaryChildParent, !0, instance)), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +function appendAllChildrenToContainer( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + !0, + instance + )), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + if (null !== workInProgress.firstEffect) { + var container = portalOrRoot.containerInfo, + newChildSet = createChildNodeSet(container); + appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); + portalOrRoot.pendingChildren = newChildSet; + workInProgress.effectTag |= 4; + completeRoot(container, newChildSet); + } +}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + type = current.stateNode; + var oldProps = current.memoizedProps; + if ((current = null === workInProgress.firstEffect) && oldProps === newProps) + workInProgress.stateNode = type; + else { + var recyclableInstance = workInProgress.stateNode; + requiredContext(contextStackCursor$1.current); + var updatePayload = null; + oldProps !== newProps && + ((oldProps = diffProperties( + null, + oldProps, + newProps, + recyclableInstance.canonical.viewConfig.validAttributes + )), + (recyclableInstance.canonical.currentProps = newProps), + (updatePayload = oldProps)); + current && null === updatePayload + ? (workInProgress.stateNode = type) + : ((newProps = updatePayload), + (recyclableInstance = type.node), + (type = { + node: current + ? null !== newProps + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) + : null !== newProps + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), + canonical: type.canonical + }), + (workInProgress.stateNode = type), + current + ? (workInProgress.effectTag |= 4) + : appendAllChildren(type, workInProgress, !1, !1)); + } +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && + ((current = requiredContext(rootInstanceStackCursor.current)), + (oldText = requiredContext(contextStackCursor$1.current)), + (workInProgress.stateNode = createTextInstance( + newText, + current, + oldText, + workInProgress + )), + (workInProgress.effectTag |= 4)); +}; +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + newProps = workInProgress.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + workInProgress.effectTag &= -3; + updateHostContainer(workInProgress); + break; + case 5: + popHostContext(workInProgress); + renderExpirationTime = requiredContext(rootInstanceStackCursor.current); + var type = workInProgress.type; + if (null !== current && null != workInProgress.stateNode) + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + renderExpirationTime + ), + current.ref !== workInProgress.ref && + (workInProgress.effectTag |= 128); + else if (newProps) { + requiredContext(contextStackCursor$1.current); + current = nextReactTag; + nextReactTag += 2; + type = getViewConfigForType(type); + var updatePayload = diffProperties( + null, + emptyObject, + newProps, + type.validAttributes + ); + renderExpirationTime = createNode( + current, + type.uiViewClassName, + renderExpirationTime, + updatePayload, + workInProgress + ); + current = new ReactFabricHostComponent( + current, + type, + newProps, + workInProgress + ); + current = { node: renderExpirationTime, canonical: current }; + appendAllChildren(current, workInProgress, !1, !1); + workInProgress.stateNode = current; + null !== workInProgress.ref && (workInProgress.effectTag |= 128); + } else if (null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != workInProgress.stateNode) + updateHostText$1( + current, + workInProgress, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + renderExpirationTime = requiredContext(contextStackCursor$1.current); + workInProgress.stateNode = createTextInstance( + newProps, + current, + renderExpirationTime, + workInProgress + ); + } + break; + case 11: + break; + case 13: + newProps = workInProgress.memoizedState; + if (0 !== (workInProgress.effectTag & 64)) + return ( + (workInProgress.expirationTime = renderExpirationTime), workInProgress + ); + newProps = null !== newProps; + renderExpirationTime = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (current = current.child.sibling), + null !== current && + ((type = workInProgress.firstEffect), + null !== type + ? ((workInProgress.firstEffect = current), + (current.nextEffect = type)) + : ((workInProgress.firstEffect = workInProgress.lastEffect = current), + (current.nextEffect = null)), + (current.effectTag = 8)))); + newProps && + !renderExpirationTime && + 0 !== (workInProgress.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + newProps && (workInProgress.effectTag |= 4); + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case 10: + popProvider(workInProgress); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + return null; +} +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + case 12: + return; + case 13: + commitSuspenseComponent(finishedWork); + return; + } + switch (finishedWork.tag) { + case 1: + case 5: + case 6: + case 20: + case 19: + break; + case 3: + case 4: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + null !== newState && + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + ((retry = tracing.unstable_wrap(retry)), + retryCache.add(thenable), + thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + pendingPassiveEffectsExpirationTime = 0, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } + schedulePendingInteraction(root, expirationTime); +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + if ( + root$jscomp$0 !== workInProgressRoot || + expirationTime !== renderExpirationTime + ) + prepareFreshStack(root$jscomp$0, expirationTime), + startWorkOnPendingInteraction(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root$jscomp$0.memoizedInteractions; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + (tracing.__interactionsRef.current = prevInteractions), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !Scheduler_shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + currentTime.mode & 4 && + stopProfilerTimerIfRunningAndRecordDelta(currentTime, !0); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + (sourceFiber = tracing.unstable_wrap(sourceFiber)), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + tracing.__interactionsRef.current = prevInteractions; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var current$$1 = unitOfWork.alternate; + 0 !== (unitOfWork.mode & 4) + ? ((profilerStartTime = now$1()), + 0 > unitOfWork.actualStartTime && (unitOfWork.actualStartTime = now$1()), + (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)), + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, !0)) + : (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === current$$1 && (current$$1 = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return current$$1; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + if (0 === (workInProgress.mode & 4)) + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + else { + var fiber = workInProgress; + profilerStartTime = now$1(); + 0 > fiber.actualStartTime && (fiber.actualStartTime = now$1()); + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + } + fiber = workInProgress; + if (1 === renderExpirationTime || 1 !== fiber.childExpirationTime) { + var newChildExpirationTime = 0; + if (0 !== (fiber.mode & 4)) { + for ( + var actualDuration = fiber.actualDuration, + treeBaseDuration = fiber.selfBaseDuration, + shouldBubbleActualDurations = + null === fiber.alternate || + fiber.child !== fiber.alternate.child, + child = fiber.child; + null !== child; + + ) { + var childUpdateExpirationTime = child.expirationTime, + childChildExpirationTime = child.childExpirationTime; + childUpdateExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childUpdateExpirationTime); + childChildExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childChildExpirationTime); + shouldBubbleActualDurations && + (actualDuration += child.actualDuration); + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + fiber.actualDuration = actualDuration; + fiber.treeBaseDuration = treeBaseDuration; + } else + for (actualDuration = fiber.child; null !== actualDuration; ) + (treeBaseDuration = actualDuration.expirationTime), + (shouldBubbleActualDurations = + actualDuration.childExpirationTime), + treeBaseDuration > newChildExpirationTime && + (newChildExpirationTime = treeBaseDuration), + shouldBubbleActualDurations > newChildExpirationTime && + (newChildExpirationTime = shouldBubbleActualDurations), + (actualDuration = actualDuration.sibling); + fiber.childExpirationTime = newChildExpirationTime; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (0 !== (workInProgress.mode & 4)) { + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + fiber = workInProgress.actualDuration; + for ( + newChildExpirationTime = workInProgress.child; + null !== newChildExpirationTime; + + ) + (fiber += newChildExpirationTime.actualDuration), + (newChildExpirationTime = newChildExpirationTime.sibling); + workInProgress.actualDuration = fiber; + } + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + if (1 < finishedWork.effectTag) + if (null !== finishedWork.lastEffect) { + finishedWork.lastEffect.nextEffect = finishedWork; + var firstEffect = finishedWork.firstEffect; + } else firstEffect = finishedWork; + else firstEffect = finishedWork.firstEffect; + if (null !== firstEffect) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + childExpirationTimeBeforeCommit = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + ReactCurrentOwner$2.current = null; + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + commitTime = now$1(); + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + nextEffect.effectTag &= -3; + break; + case 6: + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + a: for (prevState = prevProps = current$$1; ; ) { + instance = prevState; + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(instance); + switch (instance.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = instance.updateQueue; + if (null !== updateQueue) { + var lastEffect = updateQueue.lastEffect; + if (null !== lastEffect) { + var firstEffect$jscomp$0 = lastEffect.next; + snapshot = firstEffect$jscomp$0; + do { + var destroy = snapshot.destroy; + if (void 0 !== destroy) { + finishedWork$jscomp$0 = instance; + try { + destroy(); + } catch (error) { + captureCommitPhaseError( + finishedWork$jscomp$0, + error + ); + } + } + snapshot = snapshot.next; + } while (snapshot !== firstEffect$jscomp$0); + } + } + break; + case 1: + safelyDetachRef(instance); + var instance$jscomp$0 = instance.stateNode; + if ( + "function" === + typeof instance$jscomp$0.componentWillUnmount + ) + try { + (instance$jscomp$0.props = instance.memoizedProps), + (instance$jscomp$0.state = instance.memoizedState), + instance$jscomp$0.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(instance, unmountError); + } + break; + case 5: + safelyDetachRef(instance); + break; + case 4: + createChildNodeSet(instance.stateNode.containerInfo); + } + if (null !== prevState.child) + (prevState.child.return = prevState), + (prevState = prevState.child); + else { + if (prevState === prevProps) break; + for (; null === prevState.sibling; ) { + if ( + null === prevState.return || + prevState.return === prevProps + ) + break a; + prevState = prevState.return; + } + prevState.sibling.return = prevState.return; + prevState = prevState.sibling; + } + } + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = firstEffect; + do + try { + for ( + effectTag = root, current$$1$jscomp$0 = expirationTime; + null !== nextEffect; + + ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + lastEffect = effectTag; + var current$$1$jscomp$1 = nextEffect.alternate; + currentRef = nextEffect; + updateQueue = current$$1$jscomp$0; + switch (currentRef.tag) { + case 0: + case 11: + case 15: + commitHookEffectList(UnmountLayout, MountLayout, currentRef); + break; + case 1: + var instance$jscomp$1 = currentRef.stateNode; + if (currentRef.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$1.componentDidMount(); + else { + var prevProps$jscomp$0 = + currentRef.elementType === currentRef.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + currentRef.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$1.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$1.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue$jscomp$0 = currentRef.updateQueue; + null !== updateQueue$jscomp$0 && + commitUpdateQueue( + currentRef, + updateQueue$jscomp$0, + instance$jscomp$1, + updateQueue + ); + break; + case 3: + var _updateQueue = currentRef.updateQueue; + if (null !== _updateQueue) { + lastEffect = null; + if (null !== currentRef.child) + switch (currentRef.child.tag) { + case 5: + lastEffect = currentRef.child.stateNode.canonical; + break; + case 1: + lastEffect = currentRef.child.stateNode; + } + commitUpdateQueue( + currentRef, + _updateQueue, + lastEffect, + updateQueue + ); + } + break; + case 5: + if (null === current$$1$jscomp$1 && currentRef.effectTag & 4) + throw ReactError( + "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + break; + case 4: + break; + case 12: + var onRender = currentRef.memoizedProps.onRender; + onRender( + currentRef.memoizedProps.id, + null === current$$1$jscomp$1 ? "mount" : "update", + currentRef.actualDuration, + currentRef.treeBaseDuration, + currentRef.actualStartTime, + commitTime, + lastEffect.memoizedInteractions + ); + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$2 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$2.canonical; + break; + default: + instanceToUse = instance$jscomp$2; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + tracing.__interactionsRef.current = childExpirationTimeBeforeCommit; + workPhase = updateExpirationTimeBeforeCommit; + } else (root.current = finishedWork), (commitTime = now$1()); + rootDoesHavePassiveEffects + ? ((rootDoesHavePassiveEffects = !1), + (rootWithPendingPassiveEffects = root), + (pendingPassiveEffectsExpirationTime = expirationTime)) + : finishPendingInteractions(root, expirationTime); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects, + expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = 0; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (var effect = root.current.firstEffect; null !== effect; ) { + try { + var finishedWork = effect; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === effect) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(effect, error); + } + effect = effect.nextEffect; + } + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 12: + workInProgress.effectTag |= 4; + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + (workInProgress.effectTag |= 4), + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function schedulePendingInteraction(root, expirationTime) { + var interactions = tracing.__interactionsRef.current; + if (0 < interactions.size) { + var pendingInteractionMap = root.pendingInteractionMap, + pendingInteractions = pendingInteractionMap.get(expirationTime); + null != pendingInteractions + ? interactions.forEach(function(interaction) { + pendingInteractions.has(interaction) || interaction.__count++; + pendingInteractions.add(interaction); + }) + : (pendingInteractionMap.set(expirationTime, new Set(interactions)), + interactions.forEach(function(interaction) { + interaction.__count++; + })); + pendingInteractionMap = tracing.__subscriberRef.current; + if (null !== pendingInteractionMap) + pendingInteractionMap.onWorkScheduled( + interactions, + 1e3 * expirationTime + root.interactionThreadID + ); + } +} +function startWorkOnPendingInteraction(root, expirationTime) { + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime >= expirationTime && + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + }); + root.memoizedInteractions = interactions; + if (0 < interactions.size) { + var subscriber = tracing.__subscriberRef.current; + if (null !== subscriber) { + root = 1e3 * expirationTime + root.interactionThreadID; + try { + subscriber.onWorkStarted(interactions, root); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + } + } +} +function finishPendingInteractions(root, committedExpirationTime) { + var earliestRemainingTimeAfterCommit = root.firstPendingTime, + subscriber = void 0; + try { + if ( + ((subscriber = tracing.__subscriberRef.current), + null !== subscriber && 0 < root.memoizedInteractions.size) + ) + subscriber.onWorkStopped( + root.memoizedInteractions, + 1e3 * committedExpirationTime + root.interactionThreadID + ); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } finally { + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime > earliestRemainingTimeAfterCommit && + (pendingInteractionMap.delete(scheduledExpirationTime), + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + if (null !== subscriber && 0 === interaction.__count) + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + })); + }); + } +} +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactFabric = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function() {}, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = 0; + isDevToolsPresent && (uninitializedFiber |= 4); + uninitializedFiber = createFiber(3, null, null, uninitializedFiber); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode.canonical; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance) + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactFabric$2 = { default: ReactFabric }, + ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; +module.exports = ReactFabric$3.default || ReactFabric$3; diff --git a/Libraries/Renderer/oss/ReactFabric-profiling.js b/Libraries/Renderer/implementations/ReactFabric-profiling.js similarity index 98% rename from Libraries/Renderer/oss/ReactFabric-profiling.js rename to Libraries/Renderer/implementations/ReactFabric-profiling.js index 74761df873a15f..9cd8fe74bcf731 100644 --- a/Libraries/Renderer/oss/ReactFabric-profiling.js +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.js @@ -11,17 +11,11 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), - FabricUIManager = require("FabricUIManager"), Scheduler = require("scheduler"), - tracing = require("scheduler/tracing"), - ExceptionsManager = require("ExceptionsManager"); + tracing = require("scheduler/tracing"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -618,7 +612,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -681,7 +675,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -710,12 +704,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -801,7 +795,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -811,7 +805,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -823,7 +817,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -837,7 +831,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -867,11 +861,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -925,9 +919,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -949,8 +943,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -958,10 +959,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1003,11 +1002,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder( + ? ReactNativePrivateInterface.UIManager.setJSResponder( to.stateNode.canonical._nativeTag, blockNativeResponder ) - : UIManager.clearJSResponder(); + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1280,14 +1279,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1355,7 +1354,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1367,7 +1366,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1484,9 +1483,25 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var nextReactTag = 2; -FabricUIManager.registerEventHandler && - FabricUIManager.registerEventHandler(dispatchEvent); +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); var ReactFabricHostComponent = (function() { function ReactFabricHostComponent( tag, @@ -1502,19 +1517,19 @@ var ReactFabricHostComponent = (function() { this._internalInstanceHandle = internalInstanceHandle; } ReactFabricHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.measure = function(callback) { - FabricUIManager.measure( + fabricMeasure( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactFabricHostComponent.prototype.measureInWindow = function(callback) { - FabricUIManager.measureInWindow( + fabricMeasureInWindow( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1526,7 +1541,7 @@ var ReactFabricHostComponent = (function() { ) { "number" !== typeof relativeToNativeNode && relativeToNativeNode instanceof ReactFabricHostComponent && - FabricUIManager.measureLayout( + fabricMeasureLayout( this._internalInstanceHandle.stateNode.node, relativeToNativeNode._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1549,7 +1564,7 @@ function createTextInstance( hostContext = nextReactTag; nextReactTag += 2; return { - node: FabricUIManager.createNode( + node: createNode( hostContext, "RCTRawText", rootContainerInstance, @@ -1569,7 +1584,7 @@ function cloneHiddenInstance(instance) { instance.canonical.viewConfig.validAttributes ); return { - node: FabricUIManager.cloneNodeWithNewProps(node, updatePayload), + node: cloneNodeWithNewProps(node, updatePayload), canonical: instance.canonical }; } @@ -4526,12 +4541,12 @@ appendAllChildren = function( node.memoizedProps, node )); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4584,12 +4599,12 @@ function appendAllChildrenToContainer( node.memoizedProps, node )); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4634,11 +4649,11 @@ updateHostContainer = function(workInProgress) { var portalOrRoot = workInProgress.stateNode; if (null !== workInProgress.firstEffect) { var container = portalOrRoot.containerInfo, - newChildSet = FabricUIManager.createChildSet(container); + newChildSet = createChildNodeSet(container); appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); portalOrRoot.pendingChildren = newChildSet; workInProgress.effectTag |= 4; - FabricUIManager.completeRoot(container, newChildSet); + completeRoot(container, newChildSet); } }; updateHostComponent$1 = function(current, workInProgress, type, newProps) { @@ -4666,17 +4681,11 @@ updateHostComponent$1 = function(current, workInProgress, type, newProps) { (type = { node: current ? null !== newProps - ? FabricUIManager.cloneNodeWithNewProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNode(recyclableInstance) + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) : null !== newProps - ? FabricUIManager.cloneNodeWithNewChildrenAndProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNodeWithNewChildren(recyclableInstance), + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), canonical: type.canonical }), (workInProgress.stateNode = type), @@ -4739,14 +4748,14 @@ function completeWork(current, workInProgress, renderExpirationTime) { requiredContext(contextStackCursor$1.current); current = nextReactTag; nextReactTag += 2; - type = ReactNativeViewConfigRegistry.get(type); + type = getViewConfigForType(type); var updatePayload = diffProperties( null, emptyObject, newProps, type.validAttributes ); - renderExpirationTime = FabricUIManager.createNode( + renderExpirationTime = createNode( current, type.uiViewClassName, renderExpirationTime, @@ -4882,7 +4891,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -5861,9 +5870,7 @@ function commitRootImpl(root, expirationTime) { safelyDetachRef(instance); break; case 4: - FabricUIManager.createChildSet( - instance.stateNode.containerInfo - ); + createChildNodeSet(instance.stateNode.containerInfo); } if (null !== prevState.child) (prevState.child.return = prevState), @@ -6947,10 +6954,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -6963,7 +6974,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6979,7 +6990,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7001,7 +7012,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7025,7 +7036,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7089,7 +7100,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7105,7 +7116,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7123,7 +7134,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7147,7 +7158,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7155,10 +7166,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance) diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js new file mode 100644 index 00000000000000..d6da48c340b9b9 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -0,0 +1,20167 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +'use strict'; + +if (__DEV__) { + (function() { +"use strict"; + +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); +var React = require("react"); +var checkPropTypes = require("prop-types/checkPropTypes"); +var Scheduler = require("scheduler"); +var tracing = require("scheduler/tracing"); + +// Do not require this module directly! Use a normal error constructor with +// template literal strings. The messages will be converted to ReactError during +// build, and in production they will be minified. + +function ReactError(message) { + var error = new Error(message); + error.name = "Invariant Violation"; + return error; +} + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; + +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; + +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; + var pluginIndex = eventPluginOrder.indexOf(pluginName); + (function() { + if (!(pluginIndex > -1)) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + } + })(); + if (plugins[pluginIndex]) { + continue; + } + (function() { + if (!pluginModule.extractEvents) { + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + } + })(); + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + (function() { + if ( + !publishEventForPlugin( + publishedEvents[eventName], + pluginModule, + eventName + ) + ) { + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + })(); + } + } +} + +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + (function() { + if (!!eventNameDispatchConfigs.hasOwnProperty(eventName)) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName + + "`." + ); + } + })(); + eventNameDispatchConfigs[eventName] = dispatchConfig; + + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName( + phasedRegistrationName, + pluginModule, + eventName + ); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName( + dispatchConfig.registrationName, + pluginModule, + eventName + ); + return true; + } + return false; +} + +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + (function() { + if (!!registrationNameModules[registrationName]) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + } + })(); + registrationNameModules[registrationName] = pluginModule; + registrationNameDependencies[registrationName] = + pluginModule.eventTypes[eventName].dependencies; + + { + var lowerCasedName = registrationName.toLowerCase(); + } +} + +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ + +/** + * Ordered list of injected plugins. + */ +var plugins = []; + +/** + * Mapping from event name to dispatch config + */ +var eventNameDispatchConfigs = {}; + +/** + * Mapping from registration name to plugin module + */ +var registrationNameModules = {}; + +/** + * Mapping from registration name to event name + */ +var registrationNameDependencies = {}; + +/** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ + +// Trust the developer to only use possibleRegistrationNames in true + +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ +function injectEventPluginOrder(injectedEventPluginOrder) { + (function() { + if (!!eventPluginOrder) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + } + })(); + // Clone the ordering so it cannot be dynamically mutated. + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} + +/** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + (function() { + if (!!namesToPlugins[pluginName]) { + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + } + })(); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} + +var invokeGuardedCallbackImpl = function( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +}; + +{ + // In DEV mode, we swap out invokeGuardedCallback for a special version + // that plays more nicely with the browser's DevTools. The idea is to preserve + // "Pause on exceptions" behavior. Because React wraps all user-provided + // functions in invokeGuardedCallback, and the production version of + // invokeGuardedCallback uses a try-catch, all user exceptions are treated + // like caught exceptions, and the DevTools won't pause unless the developer + // takes the extra step of enabling pause on caught exceptions. This is + // unintuitive, though, because even though React has caught the error, from + // the developer's perspective, the error is uncaught. + // + // To preserve the expected "Pause on exceptions" behavior, we don't use a + // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake + // DOM node, and call the user-provided callback from inside an event handler + // for that fake event. If the callback throws, the error is "captured" using + // a global event handler. But because the error happens in a different + // event loop context, it does not interrupt the normal program flow. + // Effectively, this gives us try-catch behavior without actually using + // try-catch. Neat! + + // Check that the browser supports the APIs we need to implement our special + // DEV version of invokeGuardedCallback + if ( + typeof window !== "undefined" && + typeof window.dispatchEvent === "function" && + typeof document !== "undefined" && + typeof document.createEvent === "function" + ) { + var fakeNode = document.createElement("react"); + + var invokeGuardedCallbackDev = function( + name, + func, + context, + a, + b, + c, + d, + e, + f + ) { + // If document doesn't exist we know for sure we will crash in this method + // when we call document.createEvent(). However this can cause confusing + // errors: https://github.com/facebookincubator/create-react-app/issues/3482 + // So we preemptively throw with a better message instead. + (function() { + if (!(typeof document !== "undefined")) { + throw ReactError( + "The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous." + ); + } + })(); + var evt = document.createEvent("Event"); + + // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError = true; + + // Keeps track of the value of window.event so that we can reset it + // during the callback to let user code access window.event in the + // browsers that support it. + var windowEvent = window.event; + + // Keeps track of the descriptor of window.event to restore it after event + // dispatching: https://github.com/facebook/react/issues/13688 + var windowEventDescriptor = Object.getOwnPropertyDescriptor( + window, + "event" + ); + + // Create an event handler for our fake event. We will synchronously + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. + var funcArgs = Array.prototype.slice.call(arguments, 3); + function callCallback() { + // We immediately remove the callback from event listeners so that + // nested `invokeGuardedCallback` calls do not clash. Otherwise, a + // nested call would trigger the fake event handlers of any call higher + // in the stack. + fakeNode.removeEventListener(evtType, callCallback, false); + + // We check for window.hasOwnProperty('event') to prevent the + // window.event assignment in both IE <= 10 as they throw an error + // "Member not found" in strict mode, and in Firefox which does not + // support window.event. + if ( + typeof window.event !== "undefined" && + window.hasOwnProperty("event") + ) { + window.event = windowEvent; + } + + func.apply(context, funcArgs); + didError = false; + } + + // Create a global error event handler. We use this to capture the value + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error = void 0; + // Use this to track whether the error event is ever called. + var didSetError = false; + var isCrossOriginError = false; + + function handleWindowError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + if (event.defaultPrevented) { + // Some other error handler has prevented default. + // Browsers silence the error report if this happens. + // We'll remember this to later decide whether to log it or not. + if (error != null && typeof error === "object") { + try { + error._suppressLogging = true; + } catch (inner) { + // Ignore. + } + } + } + } + + // Create a fake event type. + var evtType = "react-" + (name ? name : "invokeguardedcallback"); + + // Attach our event handlers + window.addEventListener("error", handleWindowError); + fakeNode.addEventListener(evtType, callCallback, false); + + // Synchronously dispatch our fake event. If the user-provided function + // errors, it will trigger our global error handler. + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + + if (windowEventDescriptor) { + Object.defineProperty(window, "event", windowEventDescriptor); + } + + if (didError) { + if (!didSetError) { + // The callback errored, but the error event never fired. + error = new Error( + "An error was thrown inside one of your components, but React " + + "doesn't know what it was. This is likely due to browser " + + 'flakiness. React does its best to preserve the "Pause on ' + + 'exceptions" behavior of the DevTools, which requires some ' + + "DEV-mode only tricks. It's possible that these don't work in " + + "your browser. Try triggering the error in production mode, " + + "or switching to a modern browser. If you suspect that this is " + + "actually an issue with React, please file an issue." + ); + } else if (isCrossOriginError) { + error = new Error( + "A cross-origin error was thrown. React doesn't have access to " + + "the actual error object in development. " + + "See https://fb.me/react-crossorigin-error for more information." + ); + } + this.onError(error); + } + + // Remove our event listeners + window.removeEventListener("error", handleWindowError); + }; + + invokeGuardedCallbackImpl = invokeGuardedCallbackDev; + } +} + +var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; + +// Used by Fiber to simulate a try-catch. +var hasError = false; +var caughtError = null; + +// Used by event system to capture/rethrow the first error. +var hasRethrowError = false; +var rethrowError = null; + +var reporter = { + onError: function(error) { + hasError = true; + caughtError = error; + } +}; + +/** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = false; + caughtError = null; + invokeGuardedCallbackImpl$1.apply(reporter, arguments); +} + +/** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if caughtError and rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + var error = clearCaughtError(); + if (!hasRethrowError) { + hasRethrowError = true; + rethrowError = error; + } + } +} + +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ +function rethrowCaughtError() { + if (hasRethrowError) { + var error = rethrowError; + hasRethrowError = false; + rethrowError = null; + throw error; + } +} + +function hasCaughtError() { + return hasError; +} + +function clearCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + return error; + } else { + (function() { + { + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warningWithoutStack = function() {}; + +{ + warningWithoutStack = function(condition, format) { + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + if (format === undefined) { + throw new Error( + "`warningWithoutStack(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (args.length > 8) { + // Check before the condition to catch violations early. + throw new Error( + "warningWithoutStack() currently supports at most 8 arguments." + ); + } + if (condition) { + return; + } + if (typeof console !== "undefined") { + var argsWithFormat = args.map(function(item) { + return "" + item; + }); + argsWithFormat.unshift("Warning: " + format); + + // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + Function.prototype.apply.call(console.error, console, argsWithFormat); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + throw new Error(message); + } catch (x) {} + }; +} + +var warningWithoutStack$1 = warningWithoutStack; + +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; + +function setComponentTree( + getFiberCurrentPropsFromNodeImpl, + getInstanceFromNodeImpl, + getNodeFromInstanceImpl +) { + getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode = getInstanceFromNodeImpl; + getNodeFromInstance = getNodeFromInstanceImpl; + { + !(getNodeFromInstance && getInstanceFromNode) + ? warningWithoutStack$1( + false, + "EventPluginUtils.setComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; + } +} + +var validateEventDispatches = void 0; +{ + validateEventDispatches = function(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + + var listenersIsArr = Array.isArray(dispatchListeners); + var listenersLen = listenersIsArr + ? dispatchListeners.length + : dispatchListeners + ? 1 + : 0; + + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr + ? dispatchInstances.length + : dispatchInstances + ? 1 + : 0; + + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) + ? warningWithoutStack$1(false, "EventPluginUtils: Invalid `event`.") + : void 0; + }; +} + +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); + } + event._dispatchListeners = null; + event._dispatchInstances = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return {?string} id of the first dispatch execution who's listener returns + * true, or null if no listener returned true. + */ +function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; + } + } + return null; +} + +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ +function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchInstances = null; + event._dispatchListeners = null; + return ret; +} + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ +function executeDirectDispatch(event) { + { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchInstance = event._dispatchInstances; + (function() { + if (!!Array.isArray(dispatchListener)) { + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + } + })(); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return res; +} + +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ +function hasDispatches(event) { + return !!event._dispatchListeners; +} + +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ + +function accumulateInto(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + if (Array.isArray(next)) { + current.push.apply(current, next); + return current; + } + current.push(next); + return current; + } + + if (Array.isArray(next)) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } + + return [current, next]; +} + +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; + +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function(event) { + if (event) { + executeDispatchesInOrder(event); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; +var executeDispatchesAndReleaseTopLevel = function(e) { + return executeDispatchesAndRelease(e); +}; + +function runEventsInBatch(events) { + if (events !== null) { + eventQueue = accumulateInto(eventQueue, events); + } + + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + + if (!processingEventQueue) { + return; + } + + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + (function() { + if (!!eventQueue) { + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + } + })(); + // This would be a good time to rethrow if any of the event handlers threw. + rethrowCaughtError(); +} + +function isInteractive(tag) { + return ( + tag === "button" || + tag === "input" || + tag === "select" || + tag === "textarea" + ); +} + +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + return !!(props.disabled && isInteractive(type)); + default: + return false; + } +} + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ + +/** + * Methods for injecting dependencies. + */ +var injection = { + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: injectEventPluginsByName +}; + +/** + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ +function getListener(inst, registrationName) { + var listener = void 0; + + // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not + // live here; needs to be moved to a better place soon + var stateNode = inst.stateNode; + if (!stateNode) { + // Work in progress (ex: onload events in incremental mode). + return null; + } + var props = getFiberCurrentPropsFromNode(stateNode); + if (!props) { + // Work in progress. + return null; + } + listener = props[registrationName]; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; + } + (function() { + if (!(!listener || typeof listener === "function")) { + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + } + })(); + return listener; +} + +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ +function extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = null; + for (var i = 0; i < plugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } + } + return events; +} + +function runExtractedPluginEventsInBatch( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + runEventsInBatch(events); +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var IndeterminateComponent = 2; // Before we know whether it is function or class +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedSuspenseComponent = 18; +var EventComponent = 19; +var EventTarget = 20; + +function getParent(inst) { + do { + inst = inst.return; + // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + if (inst) { + return inst; + } + return null; +} + +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + for (var tempA = instA; tempA; tempA = getParent(tempA)) { + depthA++; + } + var depthB = 0; + for (var tempB = instB; tempB; tempB = getParent(tempB)) { + depthB++; + } + + // If A is deeper, crawl up. + while (depthA - depthB > 0) { + instA = getParent(instA); + depthA--; + } + + // If B is deeper, crawl up. + while (depthB - depthA > 0) { + instB = getParent(instB); + depthB--; + } + + // Walk in lockstep until we find a match. + var depth = depthA; + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; + } + instA = getParent(instA); + instB = getParent(instB); + } + return null; +} + +/** + * Return if A is an ancestor of B. + */ +function isAncestor(instA, instB) { + while (instB) { + if (instA === instB || instA === instB.alternate) { + return true; + } + instB = getParent(instB); + } + return false; +} + +/** + * Return the parent instance of the passed-in instance. + */ +function getParentInstance(inst) { + return getParent(inst); +} + +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ +function traverseTwoPhase(inst, fn, arg) { + var path = []; + while (inst) { + path.push(inst); + inst = getParent(inst); + } + var i = void 0; + for (i = path.length; i-- > 0; ) { + fn(path[i], "captured", arg); + } + for (i = 0; i < path.length; i++) { + fn(path[i], "bubbled", arg); + } +} + +/** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * Does not invoke the callback on the nearest common ancestor because nothing + * "entered" or "left" that element. + */ + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = + event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing even a + * single one. + */ + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(inst, phase, event) { + { + !inst + ? warningWithoutStack$1(false, "Dispatching inst must not be null") + : void 0; + } + var listener = listenerAtPhase(inst, event, phase); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We cannot perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. + */ +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? getParentInstance(targetInst) : null; + traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); +} + +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} + +/* eslint valid-typeof: 0 */ + +var EVENT_POOL_SIZE = 10; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +function functionThatReturnsTrue() { + return true; +} + +function functionThatReturnsFalse() { + return false; +} + +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; + } + + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } + { + delete this[propName]; // this has a getter/setter for warnings + } + var normalize = Interface[propName]; + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === "target") { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } + + var defaultPrevented = + nativeEvent.defaultPrevented != null + ? nativeEvent.defaultPrevented + : nativeEvent.returnValue === false; + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} + +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = true; + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== "unknown") { + event.returnValue = false; + } + this.isDefaultPrevented = functionThatReturnsTrue; + }, + + stopPropagation: function() { + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== "unknown") { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } + + this.isPropagationStopped = functionThatReturnsTrue; + }, + + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, + + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function() { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + { + Object.defineProperty( + this, + propName, + getPooledWarningPropertyDefinition(propName, Interface[propName]) + ); + } + } + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; + { + Object.defineProperty( + this, + "nativeEvent", + getPooledWarningPropertyDefinition("nativeEvent", null) + ); + Object.defineProperty( + this, + "isDefaultPrevented", + getPooledWarningPropertyDefinition( + "isDefaultPrevented", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "isPropagationStopped", + getPooledWarningPropertyDefinition( + "isPropagationStopped", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "preventDefault", + getPooledWarningPropertyDefinition("preventDefault", function() {}) + ); + Object.defineProperty( + this, + "stopPropagation", + getPooledWarningPropertyDefinition("stopPropagation", function() {}) + ); + } + } +}); + +SyntheticEvent.Interface = EventInterface; + +/** + * Helper to reduce boilerplate when creating subclasses. + */ +SyntheticEvent.extend = function(Interface) { + var Super = this; + + var E = function() {}; + E.prototype = Super.prototype; + var prototype = new E(); + + function Class() { + return Super.apply(this, arguments); + } + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + + return Class; +}; + +addEventPoolingTo(SyntheticEvent); + +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ +function getPooledWarningPropertyDefinition(propName, getVal) { + var isFunction = typeof getVal === "function"; + return { + configurable: true, + set: set, + get: get + }; + + function set(val) { + var action = isFunction ? "setting the method" : "setting the property"; + warn(action, "This is effectively a no-op"); + return val; + } + + function get() { + var action = isFunction ? "accessing the method" : "accessing the property"; + var result = isFunction + ? "This is a no-op function" + : "This is set to null"; + warn(action, result); + return getVal; + } + + function warn(action, result) { + var warningCondition = false; + !warningCondition + ? warningWithoutStack$1( + false, + "This synthetic event is reused for performance reasons. If you're seeing this, " + + "you're %s `%s` on a released/nullified synthetic event. %s. " + + "If you must keep the original synthetic event around, use event.persist(). " + + "See https://fb.me/react-event-pooling for more information.", + action, + propName, + result + ) + : void 0; + } +} + +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call( + instance, + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); + return instance; + } + return new EventConstructor( + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); +} + +function releasePooledEvent(event) { + var EventConstructor = this; + (function() { + if (!(event instanceof EventConstructor)) { + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + } + })(); + event.destructor(); + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} + +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} + +/** + * `touchHistory` isn't actually on the native event, but putting it in the + * interface will ensure that it is cleaned up when pooled/destroyed. The + * `ResponderEventPlugin` will populate it appropriately. + */ +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function(nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +var TOP_TOUCH_START = "topTouchStart"; +var TOP_TOUCH_MOVE = "topTouchMove"; +var TOP_TOUCH_END = "topTouchEnd"; +var TOP_TOUCH_CANCEL = "topTouchCancel"; +var TOP_SCROLL = "topScroll"; +var TOP_SELECTION_CHANGE = "topSelectionChange"; + +function isStartish(topLevelType) { + return topLevelType === TOP_TOUCH_START; +} + +function isMoveish(topLevelType) { + return topLevelType === TOP_TOUCH_MOVE; +} + +function isEndish(topLevelType) { + return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL; +} + +var startDependencies = [TOP_TOUCH_START]; +var moveDependencies = [TOP_TOUCH_MOVE]; +var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; + +/** + * Tracks the position and time of each active touch by `touch.identifier`. We + * should typically only see IDs in the range of 1-20 because IDs get recycled + * when touches end and start again. + */ + +var MAX_TOUCH_BANK = 20; +var touchBank = []; +var touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + // If there is only one active touch, we remember its location. This prevents + // us having to loop through all of the touches all the time in the most + // common case. + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 +}; + +function timestampForTouch(touch) { + // The legacy internal implementation provides "timeStamp", which has been + // renamed to "timestamp". Let both work for now while we iron it out + // TODO (evv): rename timeStamp to timestamp in internal code + return touch.timeStamp || touch.timestamp; +} + +/** + * TODO: Instead of making gestures recompute filtered velocity, we could + * include a built in velocity computation that can be reused globally. + */ +function createTouchRecord(touch) { + return { + touchActive: true, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }; +} + +function resetTouchRecord(touchRecord, touch) { + touchRecord.touchActive = true; + touchRecord.startPageX = touch.pageX; + touchRecord.startPageY = touch.pageY; + touchRecord.startTimeStamp = timestampForTouch(touch); + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchRecord.previousPageX = touch.pageX; + touchRecord.previousPageY = touch.pageY; + touchRecord.previousTimeStamp = timestampForTouch(touch); +} + +function getTouchIdentifier(_ref) { + var identifier = _ref.identifier; + + (function() { + if (!(identifier != null)) { + throw ReactError("Touch object is missing identifier."); + } + })(); + { + !(identifier <= MAX_TOUCH_BANK) + ? warningWithoutStack$1( + false, + "Touch identifier %s is greater than maximum supported %s which causes " + + "performance issues backfilling array locations for all of the indices.", + identifier, + MAX_TOUCH_BANK + ) + : void 0; + } + return identifier; +} + +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch); + var touchRecord = touchBank[identifier]; + if (touchRecord) { + resetTouchRecord(touchRecord, touch); + } else { + touchBank[identifier] = createTouchRecord(touch); + } + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} + +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = true; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch move without a touch start.\n" + "Touch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = false; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch end without a touch start.\n" + "Touch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} + +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); + if (touchBank.length > MAX_TOUCH_BANK) { + printed += " (original size: " + touchBank.length + ")"; + } + return printed; +} + +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchMove); + } else if (isStartish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchStart); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier; + } + } else if (isEndish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchEnd); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + for (var i = 0; i < touchBank.length; i++) { + var touchTrackToCheck = touchBank[i]; + if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { + touchHistory.indexOfSingleActiveTouch = i; + break; + } + } + { + var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; + !(activeRecord != null && activeRecord.touchActive) + ? warningWithoutStack$1(false, "Cannot find single active touch.") + : void 0; + } + } + } + }, + + touchHistory: touchHistory +}; + +/** + * Accumulates items that must not be null or undefined. + * + * This is used to conserve memory by avoiding array allocations. + * + * @return {*|array<*>} An accumulation of items. + */ +function accumulate(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + return current.concat(next); + } + + if (Array.isArray(next)) { + return [current].concat(next); + } + + return [current, next]; +} + +/** + * Instance of element that should respond to touch/move types of interactions, + * as indicated explicitly by relevant callbacks. + */ +var responderInst = null; + +/** + * Count of current touches. A textInput should become responder iff the + * selection changes while there is a touch on the screen. + */ +var trackedTouchCount = 0; + +var changeResponder = function(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); + } +}; + +var eventTypes = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + + /** + * On a `scroll`, is it desired that this element become the responder? This + * is usually not needed, but should be used to retroactively infer that a + * `touchStart` had occurred during momentum scroll. During a momentum scroll, + * a touch start will be immediately followed by a scroll event if the view is + * currently scrolling. + * + * TODO: This shouldn't bubble. + */ + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: [TOP_SCROLL] + }, + + /** + * On text selection change, should this element become the responder? This + * is needed for text inputs or other views with native selection, so the + * JS view can claim the responder. + * + * TODO: This shouldn't bubble. + */ + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: [TOP_SELECTION_CHANGE] + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { + registrationName: "onResponderGrant", + dependencies: [] + }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } +}; + +/** + * + * Responder System: + * ---------------- + * + * - A global, solitary "interaction lock" on a view. + * - If a node becomes the responder, it should convey visual feedback + * immediately to indicate so, either by highlighting or moving accordingly. + * - To be the responder means, that touches are exclusively important to that + * responder view, and no other view. + * - While touches are still occurring, the responder lock can be transferred to + * a new view, but only to increasingly "higher" views (meaning ancestors of + * the current responder). + * + * Responder being granted: + * ------------------------ + * + * - Touch starts, moves, and scrolls can cause an ID to become the responder. + * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to + * the "appropriate place". + * - If nothing is currently the responder, the "appropriate place" is the + * initiating event's `targetID`. + * - If something *is* already the responder, the "appropriate place" is the + * first common ancestor of the event target and the current `responderInst`. + * - Some negotiation happens: See the timing diagram below. + * - Scrolled views automatically become responder. The reasoning is that a + * platform scroll view that isn't built on top of the responder system has + * began scrolling, and the active responder must now be notified that the + * interaction is no longer locked to it - the system has taken over. + * + * - Responder being released: + * As soon as no more touches that *started* inside of descendants of the + * *current* responderInst, an `onResponderRelease` event is dispatched to the + * current responder, and the responder lock is released. + * + * TODO: + * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that + * determines if the responder lock should remain. + * - If a view shouldn't "remain" the responder, any active touches should by + * default be considered "dead" and do not influence future negotiations or + * bubble paths. It should be as if those touches do not exist. + * -- For multitouch: Usually a translate-z will choose to "remain" responder + * after one out of many touches ended. For translate-y, usually the view + * doesn't wish to "remain" responder after one of many touches end. + * - Consider building this on top of a `stopPropagation` model similar to + * `W3C` events. + * - Ensure that `onResponderTerminate` is called on touch cancels, whether or + * not `onResponderTerminationRequest` returns `true` or `false`. + * + */ + +/* Negotiation Performed + +-----------------------+ + / \ +Process low level events to + Current Responder + wantsResponderID +determine who to perform negot-| (if any exists at all) | +iation/transition | Otherwise just pass through| +-------------------------------+----------------------------+------------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchStart| | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onStartShouldSetResponder|----->|onResponderStart (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderReject + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderStart| + | | +----------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchMove | | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onMoveShouldSetResponder |----->|onResponderMove (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderRejec| + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderMove | + | | +----------------+ + | | + | | + Some active touch started| | + inside current responder | +------------------------+ | + +------------------------->| onResponderEnd | | + | | +------------------------+ | + +---+---------+ | | + | onTouchEnd | | | + +---+---------+ | | + | | +------------------------+ | + +------------------------->| onResponderEnd | | + No active touches started| +-----------+------------+ | + inside current responder | | | + | v | + | +------------------------+ | + | | onResponderRelease | | + | +------------------------+ | + | | + + + */ + +/** + * A note about event ordering in the `EventPluginHub`. + * + * Suppose plugins are injected in the following order: + * + * `[R, S, C]` + * + * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for + * `onClick` etc) and `R` is `ResponderEventPlugin`. + * + * "Deferred-Dispatched Events": + * + * - The current event plugin system will traverse the list of injected plugins, + * in order, and extract events by collecting the plugin's return value of + * `extractEvents()`. + * - These events that are returned from `extractEvents` are "deferred + * dispatched events". + * - When returned from `extractEvents`, deferred-dispatched events contain an + * "accumulation" of deferred dispatches. + * - These deferred dispatches are accumulated/collected before they are + * returned, but processed at a later time by the `EventPluginHub` (hence the + * name deferred). + * + * In the process of returning their deferred-dispatched events, event plugins + * themselves can dispatch events on-demand without returning them from + * `extractEvents`. Plugins might want to do this, so that they can use event + * dispatching as a tool that helps them decide which events should be extracted + * in the first place. + * + * "On-Demand-Dispatched Events": + * + * - On-demand-dispatched events are not returned from `extractEvents`. + * - On-demand-dispatched events are dispatched during the process of returning + * the deferred-dispatched events. + * - They should not have side effects. + * - They should be avoided, and/or eventually be replaced with another + * abstraction that allows event plugins to perform multiple "rounds" of event + * extraction. + * + * Therefore, the sequence of event dispatches becomes: + * + * - `R`s on-demand events (if any) (dispatched by `R` on-demand) + * - `S`s on-demand events (if any) (dispatched by `S` on-demand) + * - `C`s on-demand events (if any) (dispatched by `C` on-demand) + * - `R`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `S`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `C`s extracted events (if any) (dispatched by `EventPluginHub`) + * + * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` + * on-demand dispatch returns `true` (and some other details are satisfied) the + * `onResponderGrant` deferred dispatched event is returned from + * `extractEvents`. The sequence of dispatch executions in this case + * will appear as follows: + * + * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) + * - `touchStartCapture` (`EventPluginHub` dispatches as usual) + * - `touchStart` (`EventPluginHub` dispatches as usual) + * - `responderGrant/Reject` (`EventPluginHub` dispatches as usual) + */ + +function setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var shouldSetEventType = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : topLevelType === TOP_SELECTION_CHANGE + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + + // TODO: stop one short of the current responder. + var bubbleShouldSetFrom = !responderInst + ? targetInst + : getLowestCommonAncestor(responderInst, targetInst); + + // When capturing/bubbling the "shouldSet" event, we want to skip the target + // (deepest ID) if it happens to be the current responder. The reasoning: + // It's strange to get an `onMoveShouldSetResponder` when you're *already* + // the responder. + var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; + var shouldSetEvent = ResponderSyntheticEvent.getPooled( + shouldSetEventType, + bubbleShouldSetFrom, + nativeEvent, + nativeEventTarget + ); + shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + if (skipOverBubbleShouldSetFrom) { + accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); + } else { + accumulateTwoPhaseDispatches(shouldSetEvent); + } + var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent); + if (!shouldSetEvent.isPersistent()) { + shouldSetEvent.constructor.release(shouldSetEvent); + } + + if (!wantsResponderInst || wantsResponderInst === responderInst) { + return null; + } + var extracted = void 0; + var grantEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + accumulateDirectDispatches(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminationRequestEvent.touchHistory = + ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminationRequestEvent); + var shouldSwitch = + !hasDispatches(terminationRequestEvent) || + executeDirectDispatch(terminationRequestEvent); + if (!terminationRequestEvent.isPersistent()) { + terminationRequestEvent.constructor.release(terminationRequestEvent); + } + + if (shouldSwitch) { + var terminateEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(rejectEvent); + extracted = accumulate(extracted, rejectEvent); + } + } else { + extracted = accumulate(extracted, grantEvent); + changeResponder(wantsResponderInst, blockHostResponder); + } + return extracted; +} + +/** + * A transfer is a negotiation between a currently set responder and the next + * element to claim responder status. Any start event could trigger a transfer + * of responderInst. Any move event could trigger a transfer. + * + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @return {boolean} True if a transfer of responder could possibly occur. + */ +function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { + return ( + topLevelInst && + // responderIgnoreScroll: We are trying to migrate away from specifically + // tracking native scroll events here and responderIgnoreScroll indicates we + // will send topTouchCancel to handle canceling touch events instead + ((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) || + (trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ); +} + +/** + * Returns whether or not this touch end event makes it such that there are no + * longer any touches that started inside of the current `responderInst`. + * + * @param {NativeEvent} nativeEvent Native touch end event. + * @return {boolean} Whether or not this touch end event ends the responder. + */ +function noResponderTouches(nativeEvent) { + var touches = nativeEvent.touches; + if (!touches || touches.length === 0) { + return true; + } + for (var i = 0; i < touches.length; i++) { + var activeTouch = touches[i]; + var target = activeTouch.target; + if (target !== null && target !== undefined && target !== 0) { + // Is the original touch location inside of the current responder? + var targetInst = getInstanceFromNode(target); + if (isAncestor(responderInst, targetInst)) { + return false; + } + } + } + return true; +} + +var ResponderEventPlugin = { + /* For unit testing only */ + _getResponder: function() { + return responderInst; + }, + + eventTypes: eventTypes, + + /** + * We must be resilient to `targetInst` being `null` on `touchMove` or + * `touchEnd`. On certain platforms, this means that a native scroll has + * assumed control and the original touch targets are destroyed. + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) { + trackedTouchCount += 1; + } else if (isEndish(topLevelType)) { + if (trackedTouchCount >= 0) { + trackedTouchCount -= 1; + } else { + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ); + return null; + } + } + + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + + var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) + ? setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) + : null; + // Responder may or may not have transferred on a new touch start/move. + // Regardless, whoever is the responder after any potential transfer, we + // direct all touch start/move/ends to them in the form of + // `onResponderMove/Start/End`. These will be called for *every* additional + // finger that move/start/end, dispatched directly to whoever is the + // current responder at that moment, until the responder is "released". + // + // These multiple individual change touch events are are always bookended + // by `onResponderGrant`, and one of + // (`onResponderRelease/onResponderTerminate`). + var isResponderTouchStart = responderInst && isStartish(topLevelType); + var isResponderTouchMove = responderInst && isMoveish(topLevelType); + var isResponderTouchEnd = responderInst && isEndish(topLevelType); + var incrementalTouch = isResponderTouchStart + ? eventTypes.responderStart + : isResponderTouchMove + ? eventTypes.responderMove + : isResponderTouchEnd + ? eventTypes.responderEnd + : null; + + if (incrementalTouch) { + var gesture = ResponderSyntheticEvent.getPooled( + incrementalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(gesture); + extracted = accumulate(extracted, gesture); + } + + var isResponderTerminate = + responderInst && topLevelType === TOP_TOUCH_CANCEL; + var isResponderRelease = + responderInst && + !isResponderTerminate && + isEndish(topLevelType) && + noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate + ? eventTypes.responderTerminate + : isResponderRelease + ? eventTypes.responderRelease + : null; + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled( + finalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + return extracted; + }, + + GlobalResponderHandler: null, + + injection: { + /** + * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler + * Object that handles any change in responder. Use this to inject + * integration with an existing touch handling system etc. + */ + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } +}; + +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + +var ReactNativeBridgeEventPlugin = { + eventTypes: eventTypes$1, + + /** + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (targetInst == null) { + // Probably a node belonging to another renderer's tree. + return null; + } + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; + (function() { + if (!(bubbleDispatchConfig || directDispatchConfig)) { + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + } + })(); + var event = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) { + accumulateTwoPhaseDispatches(event); + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; + } + return event; + } +}; + +var ReactNativeEventPluginOrder = [ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]; + +/** + * Make sure essential globals are available and are patched correctly. Please don't remove this + * line. Bundles created by react-packager `require` it before executing any application code. This + * ensures it exists in the dependency graph and can be `require`d. + * TODO: require this in packager, not in React #10932517 + */ +// Module provided by RN: +/** + * Inject module for resolving DOM hierarchy and plugin ordering. + */ +injection.injectEventPluginOrder(ReactNativeEventPluginOrder); + +/** + * Some important event plugins included by default (without having to require + * them). + */ +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); + +var instanceCache = {}; +var instanceProps = {}; + +function precacheFiberNode(hostInst, tag) { + instanceCache[tag] = hostInst; +} + +function uncacheFiberNode(tag) { + delete instanceCache[tag]; + delete instanceProps[tag]; +} + +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} + +function getTagFromInstance(inst) { + var tag = inst.stateNode._nativeTag; + if (tag === undefined) { + tag = inst.stateNode.canonical._nativeTag; + } + (function() { + if (!tag) { + throw ReactError("All native instances should have a tag."); + } + })(); + return tag; +} + +function getFiberCurrentPropsFromNode$1(stateNode) { + return instanceProps[stateNode._nativeTag] || null; +} + +function updateFiberProps(tag, props) { + instanceProps[tag] = props; +} + +// Use to restore controlled state after a change event has fired. + +var restoreImpl = null; +var restoreTarget = null; +var restoreQueue = null; + +function restoreStateOfTarget(target) { + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here + var internalInstance = getInstanceFromNode(target); + if (!internalInstance) { + // Unmounted + return; + } + (function() { + if (!(typeof restoreImpl === "function")) { + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + restoreImpl(internalInstance.stateNode, internalInstance.type, props); +} + +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} + +function restoreStateIfNeeded() { + if (!restoreTarget) { + return; + } + var target = restoreTarget; + var queuedTargets = restoreQueue; + restoreTarget = null; + restoreQueue = null; + + restoreStateOfTarget(target); + if (queuedTargets) { + for (var i = 0; i < queuedTargets.length; i++) { + restoreStateOfTarget(queuedTargets[i]); + } + } +} + +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. + +// Defaults +var _batchedUpdatesImpl = function(fn, bookkeeping) { + return fn(bookkeeping); +}; +var _flushInteractiveUpdatesImpl = function() {}; + +var isBatching = false; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(bookkeeping); + } + isBatching = true; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdatesImpl(); + restoreStateIfNeeded(); + } + } +} + +function setBatchingImplementation( + batchedUpdatesImpl, + interactiveUpdatesImpl, + flushInteractiveUpdatesImpl +) { + _batchedUpdatesImpl = batchedUpdatesImpl; + _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl; +} + +/** + * Version of `ReactBrowserEventEmitter` that works on the receiving side of a + * serialized worker boundary. + */ + +// Shared default empty native event - conserve memory. +var EMPTY_NATIVE_EVENT = {}; + +/** + * Selects a subsequence of `Touch`es, without destroying `touches`. + * + * @param {Array} touches Deserialized touch objects. + * @param {Array} indices Indices by which to pull subsequence. + * @return {Array} Subsequence of touch objects. + */ +var touchSubsequence = function(touches, indices) { + var ret = []; + for (var i = 0; i < indices.length; i++) { + ret.push(touches[indices[i]]); + } + return ret; +}; + +/** + * TODO: Pool all of this. + * + * Destroys `touches` by removing touch objects at indices `indices`. This is + * to maintain compatibility with W3C touch "end" events, where the active + * touches don't include the set that has just been "ended". + * + * @param {Array} touches Deserialized touch objects. + * @param {Array} indices Indices to remove from `touches`. + * @return {Array} Subsequence of removed touch objects. + */ +var removeTouchesAtIndices = function(touches, indices) { + var rippedOut = []; + // use an unsafe downcast to alias to nullable elements, + // so we can delete and then compact. + var temp = touches; + for (var i = 0; i < indices.length; i++) { + var index = indices[i]; + rippedOut.push(touches[index]); + temp[index] = null; + } + var fillAt = 0; + for (var j = 0; j < temp.length; j++) { + var cur = temp[j]; + if (cur !== null) { + temp[fillAt++] = cur; + } + } + temp.length = fillAt; + return rippedOut; +}; + +/** + * Internal version of `receiveEvent` in terms of normalized (non-tag) + * `rootNodeID`. + * + * @see receiveEvent. + * + * @param {rootNodeID} rootNodeID React root node ID that event occurred on. + * @param {TopLevelType} topLevelType Top level type of event. + * @param {?object} nativeEventParam Object passed from native. + */ +function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { + var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT; + var inst = getInstanceFromTag(rootNodeID); + batchedUpdates(function() { + runExtractedPluginEventsInBatch( + topLevelType, + inst, + nativeEvent, + nativeEvent.target + ); + }); + // React Native doesn't use ReactControlledComponent but if it did, here's + // where it would do it. +} + +/** + * Publicly exposed method on module for native objc to invoke when a top + * level event is extracted. + * @param {rootNodeID} rootNodeID React root node ID that event occurred on. + * @param {TopLevelType} topLevelType Top level type of event. + * @param {object} nativeEventParam Object passed from native. + */ +function receiveEvent(rootNodeID, topLevelType, nativeEventParam) { + _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); +} + +/** + * Simple multi-wrapper around `receiveEvent` that is intended to receive an + * efficient representation of `Touch` objects, and other information that + * can be used to construct W3C compliant `Event` and `Touch` lists. + * + * This may create dispatch behavior that differs than web touch handling. We + * loop through each of the changed touches and receive it as a single event. + * So two `touchStart`/`touchMove`s that occur simultaneously are received as + * two separate touch event dispatches - when they arguably should be one. + * + * This implementation reuses the `Touch` objects themselves as the `Event`s + * since we dispatch an event for each touch (though that might not be spec + * compliant). The main purpose of reusing them is to save allocations. + * + * TODO: Dispatch multiple changed touches in one event. The bubble path + * could be the first common ancestor of all the `changedTouches`. + * + * One difference between this behavior and W3C spec: cancelled touches will + * not appear in `.touches`, or in any future `.touches`, though they may + * still be "actively touching the surface". + * + * Web desktop polyfills only need to construct a fake touch event with + * identifier 0, also abandoning traditional click handlers. + */ +function receiveTouches(eventTopLevelType, touches, changedIndices) { + var changedTouches = + eventTopLevelType === "topTouchEnd" || + eventTopLevelType === "topTouchCancel" + ? removeTouchesAtIndices(touches, changedIndices) + : touchSubsequence(touches, changedIndices); + + for (var jj = 0; jj < changedTouches.length; jj++) { + var touch = changedTouches[jj]; + // Touch objects can fulfill the role of `DOM` `Event` objects if we set + // the `changedTouches`/`touches`. This saves allocations. + touch.changedTouches = changedTouches; + touch.touches = touches; + var nativeEvent = touch; + var rootNodeID = null; + var target = nativeEvent.target; + if (target !== null && target !== undefined) { + if (target < 1) { + { + warningWithoutStack$1( + false, + "A view is reporting that a touch occurred on tag zero." + ); + } + } else { + rootNodeID = target; + } + } + // $FlowFixMe Shouldn't we *not* call it if rootNodeID is null? + _receiveRootNodeIDEvent(rootNodeID, eventTopLevelType, nativeEvent); + } +} + +// Module provided by RN: +var ReactNativeGlobalResponderHandler = { + onChange: function(from, to, blockNativeResponder) { + if (to !== null) { + var tag = to.stateNode._nativeTag; + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); + } else { + ReactNativePrivateInterface.UIManager.clearJSResponder(); + } + } +}; + +// Module provided by RN: +/** + * Register the event emitter with the native bridge + */ +ReactNativePrivateInterface.RCTEventEmitter.register({ + receiveEvent: receiveEvent, + receiveTouches: receiveTouches +}); + +setComponentTree( + getFiberCurrentPropsFromNode$1, + getInstanceFromTag, + getTagFromInstance +); + +ResponderEventPlugin.injection.injectGlobalResponderHandler( + ReactNativeGlobalResponderHandler +); + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ + +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + +function get(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +// Prevent newer renderers from RTE when used with older react package versions. +// Current owner and dispatcher used to share the same ref, +// but PR #14548 split them out to better support the react-debug-tools package. +if (!ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher")) { + ReactSharedInternals.ReactCurrentDispatcher = { + current: null + }; +} + +// The Symbol used to tag the ReactElement-like types. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var hasSymbol = typeof Symbol === "function" && Symbol.for; + +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 0xeac7; +var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 0xeaca; +var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 0xeacb; +var REACT_STRICT_MODE_TYPE = hasSymbol + ? Symbol.for("react.strict_mode") + : 0xeacc; +var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 0xead2; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 0xeace; + +var REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol.for("react.forward_ref") + : 0xead0; +var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 0xead1; +var REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 0xead3; +var REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 0xead4; +var REACT_EVENT_COMPONENT_TYPE = hasSymbol + ? Symbol.for("react.event_component") + : 0xead5; +var REACT_EVENT_TARGET_TYPE = hasSymbol + ? Symbol.for("react.event_target") + : 0xead6; + +// React event targets +var REACT_EVENT_TARGET_TOUCH_HIT = hasSymbol + ? Symbol.for("react.event_target.touch_hit") + : 0xead7; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = "@@iterator"; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== "object") { + return null; + } + var maybeIterator = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === "function") { + return maybeIterator; + } + return null; +} + +var Pending = 0; +var Resolved = 1; +var Rejected = 2; + +function refineResolvedLazyComponent(lazyComponent) { + return lazyComponent._status === Resolved ? lazyComponent._result : null; +} + +// Re-export dynamic flags from the fbsource version. +var _require = require("../shims/ReactFeatureFlags"); + +var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; + +var enableUserTimingAPI = true; +var enableProfilerTimer = true; +var enableSchedulerTracing = true; +var enableSuspenseServerRenderer = false; + +var debugRenderPhaseSideEffectsForStrictMode = true; + +var disableYielding = false; + +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; +var warnAboutDeprecatedLifecycles = true; +var warnAboutDeprecatedSetNativeProps = true; +var enableEventAPI = false; + +// Only used in www builds. + +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ""; + return ( + outerType.displayName || + (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName) + ); +} + +function getComponentName(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + { + if (typeof type.tag === "number") { + warningWithoutStack$1( + false, + "Received an unexpected object in getComponentName(). " + + "This is likely a bug in React. Please file an issue." + ); + } + } + if (typeof type === "function") { + return type.displayName || type.name || null; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, "ForwardRef"); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: { + var thenable = type; + var resolvedThenable = refineResolvedLazyComponent(thenable); + if (resolvedThenable) { + return getComponentName(resolvedThenable); + } + break; + } + case REACT_EVENT_COMPONENT_TYPE: { + if (enableEventAPI) { + var eventComponent = type; + var displayName = eventComponent.displayName; + if (displayName !== undefined) { + return displayName; + } + } + break; + } + case REACT_EVENT_TARGET_TYPE: { + if (enableEventAPI) { + var eventTarget = type; + if (eventTarget.type === REACT_EVENT_TARGET_TOUCH_HIT) { + return "TouchHitTarget"; + } + var _displayName = eventTarget.displayName; + if (_displayName !== undefined) { + return _displayName; + } + } + } + } + } + return null; +} + +// Don't change these two values. They're used by React Dev Tools. +var NoEffect = /* */ 0; +var PerformedWork = /* */ 1; + +// You can change the rest (and add more). +var Placement = /* */ 2; +var Update = /* */ 4; +var PlacementAndUpdate = /* */ 6; +var Deletion = /* */ 8; +var ContentReset = /* */ 16; +var Callback = /* */ 32; +var DidCapture = /* */ 64; +var Ref = /* */ 128; +var Snapshot = /* */ 256; +var Passive = /* */ 512; + +// Passive & Update & Callback & Ref & Snapshot +var LifecycleEffectMask = /* */ 932; + +// Union of all host effects +var HostEffectMask = /* */ 1023; + +var Incomplete = /* */ 1024; +var ShouldCapture = /* */ 2048; + +var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; + +var MOUNTING = 1; +var MOUNTED = 2; +var UNMOUNTED = 3; + +function isFiberMountedImpl(fiber) { + var node = fiber; + if (!fiber.alternate) { + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + while (node.return) { + node = node.return; + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + } + } else { + while (node.return) { + node = node.return; + } + } + if (node.tag === HostRoot) { + // TODO: Check if this was a nested HostRoot when used with + // renderContainerIntoSubtree. + return MOUNTED; + } + // If we didn't hit the root, that means that we're in an disconnected tree + // that has been unmounted. + return UNMOUNTED; +} + +function isFiberMounted(fiber) { + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function isMounted(component) { + { + var owner = ReactCurrentOwner$1.current; + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + !instance._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing isMounted inside its render() function. " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(ownerFiber.type) || "A component" + ) + : void 0; + instance._warnedAboutRefsInRender = true; + } + } + + var fiber = get(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + (function() { + if (!(isFiberMountedImpl(fiber) === MOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); +} + +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var state = isFiberMountedImpl(fiber); + (function() { + if (!(state !== UNMOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (state === MOUNTING) { + return null; + } + return fiber; + } + // If we have two possible branches, we'll walk backwards up to the root + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. + var a = fiber; + var b = alternate; + while (true) { + var parentA = a.return; + if (parentA === null) { + // We're at the root. + break; + } + var parentB = parentA.alternate; + if (parentB === null) { + // There is no alternate. This is an unusual case. Currently, it only + // happens when a Suspense component is hidden. An extra fragment fiber + // is inserted in between the Suspense fiber and its children. Skip + // over this extra fragment fiber and proceed to the next parent. + var nextParent = parentA.return; + if (nextParent !== null) { + a = b = nextParent; + continue; + } + // If there's no parent, we're at the root. + break; + } + + // If both copies of the parent fiber point to the same child, we can + // assume that the child is current. This happens when we bailout on low + // priority: the bailed out fiber's child reuses the current child. + if (parentA.child === parentB.child) { + var child = parentA.child; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } + child = child.sibling; + } + // We should never have an alternate for any mounting node. So the only + // way this could possibly happen is if this was unmounted, if at all. + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } + + if (a.return !== b.return) { + // The return pointer of A and the return pointer of B point to different + // fibers. We assume that return pointers never criss-cross, so A must + // belong to the child set of A.return, and B must belong to the child + // set of B.return. + a = parentA; + b = parentB; + } else { + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set + var didFindChild = false; + var _child = parentA.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + (function() { + if (!didFindChild) { + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + })(); + } + } + + (function() { + if (!(a.alternate === b)) { + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. + (function() { + if (!(a.tag === HostRoot)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } + // Otherwise B has to be current branch. + return alternate; +} + +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + if (!currentParent) { + return null; + } + + // Next we'll drill down this component to find the first HostComponent/Text. + var node = currentParent; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + return node; + } else if (node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === currentParent) { + return null; + } + while (!node.sibling) { + if (!node.return || node.return === currentParent) { + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + // Flow needs the return null here, but ESLint complains about it. + // eslint-disable-next-line no-unreachable + return null; +} + +// Modules provided by RN: +var emptyObject = {}; + +/** + * Create a payload that contains all the updates between two sets of props. + * + * These helpers are all encapsulated into a single module, because they use + * mutation as a performance optimization which leads to subtle shared + * dependencies between the code paths. To avoid this mutable state leaking + * across modules, I've kept them isolated to this module. + */ + +// Tracks removed keys +var removedKeys = null; +var removedKeyCount = 0; + +function defaultDiffer(prevProp, nextProp) { + if (typeof nextProp !== "object" || nextProp === null) { + // Scalars have already been checked for equality + return true; + } else { + // For objects and arrays, the default diffing algorithm is a deep compare + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); + } +} + +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) { + var i = node.length; + while (i-- && removedKeyCount > 0) { + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + } + } else if (node && removedKeyCount > 0) { + var obj = node; + for (var propKey in removedKeys) { + if (!removedKeys[propKey]) { + continue; + } + var nextProp = obj[propKey]; + if (nextProp === undefined) { + continue; + } + + var attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (typeof nextProp === "function") { + nextProp = true; + } + if (typeof nextProp === "undefined") { + nextProp = null; + } + + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + removedKeys[propKey] = false; + removedKeyCount--; + } + } +} + +function diffNestedArrayProperty( + updatePayload, + prevArray, + nextArray, + validAttributes +) { + var minLength = + prevArray.length < nextArray.length ? prevArray.length : nextArray.length; + var i = void 0; + for (i = 0; i < minLength; i++) { + // Diff any items in the array in the forward direction. Repeated keys + // will be overwritten by later values. + updatePayload = diffNestedProperty( + updatePayload, + prevArray[i], + nextArray[i], + validAttributes + ); + } + for (; i < prevArray.length; i++) { + // Clear out all remaining properties. + updatePayload = clearNestedProperty( + updatePayload, + prevArray[i], + validAttributes + ); + } + for (; i < nextArray.length; i++) { + // Add all remaining properties. + updatePayload = addNestedProperty( + updatePayload, + nextArray[i], + validAttributes + ); + } + return updatePayload; +} + +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) { + // If no properties have been added, then we can bail out quickly on object + // equality. + return updatePayload; + } + + if (!prevProp || !nextProp) { + if (nextProp) { + return addNestedProperty(updatePayload, nextProp, validAttributes); + } + if (prevProp) { + return clearNestedProperty(updatePayload, prevProp, validAttributes); + } + return updatePayload; + } + + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { + // Both are leaves, we can diff the leaves. + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + } + + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + // Both are arrays, we can diff the arrays. + return diffNestedArrayProperty( + updatePayload, + prevProp, + nextProp, + validAttributes + ); + } + + if (Array.isArray(prevProp)) { + return diffProperties( + updatePayload, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(prevProp), + // $FlowFixMe - We know that this isn't an array because of above flow. + nextProp, + validAttributes + ); + } + + return diffProperties( + updatePayload, + prevProp, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} + +/** + * addNestedProperty takes a single set of props and valid attribute + * attribute configurations. It processes each prop and adds it to the + * updatePayload. + */ +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) { + return updatePayload; + } + + if (!Array.isArray(nextProp)) { + // Add each property of the leaf. + return addProperties(updatePayload, nextProp, validAttributes); + } + + for (var i = 0; i < nextProp.length; i++) { + // Add all the properties of the array. + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + } + + return updatePayload; +} + +/** + * clearNestedProperty takes a single set of props and valid attributes. It + * adds a null sentinel to the updatePayload, for each prop key. + */ +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) { + return updatePayload; + } + + if (!Array.isArray(prevProp)) { + // Add each property of the leaf. + return clearProperties(updatePayload, prevProp, validAttributes); + } + + for (var i = 0; i < prevProp.length; i++) { + // Add all the properties of the array. + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + } + return updatePayload; +} + +/** + * diffProperties takes two sets of props and a set of valid attributes + * and write to updatePayload the values that changed or were deleted. + * If no updatePayload is provided, a new one is created and returned if + * anything changed. + */ +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig = void 0; + var nextProp = void 0; + var prevProp = void 0; + + for (var propKey in nextProps) { + attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + prevProp = prevProps[propKey]; + nextProp = nextProps[propKey]; + + // functions are converted to booleans as markers that the associated + // events should be sent from native. + if (typeof nextProp === "function") { + nextProp = true; + // If nextProp is not a function, then don't bother changing prevProp + // since nextProp will win and go into the updatePayload regardless. + if (typeof prevProp === "function") { + prevProp = true; + } + } + + // An explicit value of undefined is treated as a null because it overrides + // any other preceding value. + if (typeof nextProp === "undefined") { + nextProp = null; + if (typeof prevProp === "undefined") { + prevProp = null; + } + } + + if (removedKeys) { + removedKeys[propKey] = false; + } + + if (updatePayload && updatePayload[propKey] !== undefined) { + // Something else already triggered an update to this key because another + // value diffed. Since we're now later in the nested arrays our value is + // more important so we need to calculate it and override the existing + // value. It doesn't matter if nothing changed, we'll set it anyway. + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + continue; + } + + if (prevProp === nextProp) { + continue; // nothing changed + } + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + if (defaultDiffer(prevProp, nextProp)) { + // a normal leaf has changed + (updatePayload || (updatePayload = {}))[propKey] = nextProp; + } + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var shouldUpdate = + prevProp === undefined || + (typeof attributeConfig.diff === "function" + ? attributeConfig.diff(prevProp, nextProp) + : defaultDiffer(prevProp, nextProp)); + if (shouldUpdate) { + var _nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + (updatePayload || (updatePayload = {}))[propKey] = _nextValue; + } + } else { + // default: fallthrough case when nested properties are defined + removedKeys = null; + removedKeyCount = 0; + // We think that attributeConfig is not CustomAttributeConfiguration at + // this point so we assume it must be AttributeConfiguration. + updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + ); + if (removedKeyCount > 0 && updatePayload) { + restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ); + removedKeys = null; + } + } + } + + // Also iterate through all the previous props to catch any that have been + // removed and make sure native gets the signal so it can reset them to the + // default. + for (var _propKey in prevProps) { + if (nextProps[_propKey] !== undefined) { + continue; // we've already covered this key in the previous pass + } + attributeConfig = validAttributes[_propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (updatePayload && updatePayload[_propKey] !== undefined) { + // This was already updated to a diff result earlier. + continue; + } + + prevProp = prevProps[_propKey]; + if (prevProp === undefined) { + continue; // was already empty anyway + } + // Pattern match on: attributeConfig + if ( + typeof attributeConfig !== "object" || + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration | !Object + // Flag the leaf property for removal by sending a sentinel. + (updatePayload || (updatePayload = {}))[_propKey] = null; + if (!removedKeys) { + removedKeys = {}; + } + if (!removedKeys[_propKey]) { + removedKeys[_propKey] = true; + removedKeyCount++; + } + } else { + // default: + // This is a nested attribute configuration where all the properties + // were removed so we need to go through and clear out all of them. + updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ); + } + } + return updatePayload; +} + +/** + * addProperties adds all the valid props to the payload after being processed. + */ +function addProperties(updatePayload, props, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, emptyObject, props, validAttributes); +} + +/** + * clearProperties clears all the previous props by adding a null sentinel + * to the payload for each valid key. + */ +function clearProperties(updatePayload, prevProps, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, prevProps, emptyObject, validAttributes); +} + +function create(props, validAttributes) { + return addProperties( + null, // updatePayload + props, + validAttributes + ); +} + +function diff(prevProps, nextProps, validAttributes) { + return diffProperties( + null, // updatePayload + prevProps, + nextProps, + validAttributes + ); +} + +/** + * In the future, we should cleanup callbacks by cancelling them instead of + * using this. + */ +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if (!callback) { + return undefined; + } + // This protects against createClass() components. + // We don't know if there is code depending on it. + // We intentionally don't use isMounted() because even accessing + // isMounted property on a React ES6 class will trigger a warning. + if (typeof context.__isMounted === "boolean") { + if (!context.__isMounted) { + return undefined; + } + } + + // FIXME: there used to be other branches that protected + // against unmounted host components. But RN host components don't + // define isMounted() anymore, so those checks didn't do anything. + + // They caused false positive warning noise so we removed them: + // https://github.com/facebook/react-native/issues/18868#issuecomment-413579095 + + // However, this means that the callback is NOT guaranteed to be safe + // for host components. The solution we should implement is to make + // UIManager.measure() and similar calls truly cancelable. Then we + // can change our own code calling them to cancel when something unmounts. + + return callback.apply(context, arguments); + }; +} + +function throwOnStylesProp(component, props) { + if (props.styles !== undefined) { + var owner = component._owner || null; + var name = component.constructor.displayName; + var msg = + "`styles` is not a supported property of `" + + name + + "`, did " + + "you mean `style` (singular)?"; + if (owner && owner.constructor && owner.constructor.displayName) { + msg += + "\n\nCheck the `" + + owner.constructor.displayName + + "` parent " + + " component."; + } + throw new Error(msg); + } +} + +function warnForStyleProps(props, validAttributes) { + for (var key in validAttributes.style) { + if (!(validAttributes[key] || props[key] === undefined)) { + console.error( + "You are setting the style `{ " + + key + + ": ... }` as a prop. You " + + "should nest it in a style object. " + + "E.g. `{ style: { " + + key + + ": ... } }`" + ); + } + } +} + +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +// Modules provided by RN: +/** + * This component defines the same methods as NativeMethodsMixin but without the + * findNodeHandle wrapper. This wrapper is unnecessary for HostComponent views + * and would also result in a circular require.js dependency (since + * ReactNativeFiber depends on this component and NativeMethodsMixin depends on + * ReactNativeFiber). + */ + +var ReactNativeFiberHostComponent = (function() { + function ReactNativeFiberHostComponent(tag, viewConfig) { + _classCallCheck(this, ReactNativeFiberHostComponent); + + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; + } + + ReactNativeFiberHostComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + + ReactNativeFiberHostComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + + ReactNativeFiberHostComponent.prototype.measure = function measure(callback) { + ReactNativePrivateInterface.UIManager.measure( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactNativeFiberHostComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + ReactNativePrivateInterface.UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactNativeFiberHostComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } else if ( + relativeToNativeNode.canonical && + relativeToNativeNode.canonical._nativeTag + ) { + relativeNode = relativeToNativeNode.canonical._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + this._nativeTag, + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + + ReactNativeFiberHostComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + warnForStyleProps(nativeProps, this.viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, this.viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeFiberHostComponent; +})(); + +// Renderers that don't support persistence +// can re-export everything from this module. + +function shim() { + (function() { + { + throw ReactError( + "The current renderer does not support persistence. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Persistence (when unsupported) +var supportsPersistence = false; +var cloneInstance = shim; +var createContainerChildSet = shim; +var appendChildToContainerChildSet = shim; +var finalizeContainerChildren = shim; +var replaceContainerChildren = shim; +var cloneHiddenInstance = shim; +var cloneHiddenTextInstance = shim; + +// Renderers that don't support hydration +// can re-export everything from this module. + +function shim$1() { + (function() { + { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Hydration (when unsupported) + +var supportsHydration = false; +var canHydrateInstance = shim$1; +var canHydrateTextInstance = shim$1; +var canHydrateSuspenseInstance = shim$1; +var isSuspenseInstancePending = shim$1; +var isSuspenseInstanceFallback = shim$1; +var registerSuspenseInstanceRetry = shim$1; +var getNextHydratableSibling = shim$1; +var getFirstHydratableChild = shim$1; +var hydrateInstance = shim$1; +var hydrateTextInstance = shim$1; +var getNextHydratableInstanceAfterSuspenseInstance = shim$1; +var clearSuspenseBoundary = shim$1; +var clearSuspenseBoundaryFromContainer = shim$1; +var didNotMatchHydratedContainerTextInstance = shim$1; +var didNotMatchHydratedTextInstance = shim$1; +var didNotHydrateContainerInstance = shim$1; +var didNotHydrateInstance = shim$1; +var didNotFindHydratableContainerInstance = shim$1; +var didNotFindHydratableContainerTextInstance = shim$1; +var didNotFindHydratableContainerSuspenseInstance = shim$1; +var didNotFindHydratableInstance = shim$1; +var didNotFindHydratableTextInstance = shim$1; +var didNotFindHydratableSuspenseInstance = shim$1; + +// Modules provided by RN: +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Unused +// Unused + +var UPDATE_SIGNAL = {}; +{ + Object.freeze(UPDATE_SIGNAL); +} + +// Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. +var nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + if (tag % 10 === 1) { + tag += 2; + } + nextReactTag = tag + 2; + return tag; +} + +function recursivelyUncacheFiberNode(node) { + if (typeof node === "number") { + // Leaf node (eg text) + uncacheFiberNode(node); + } else { + uncacheFiberNode(node._nativeTag); + + node._children.forEach(recursivelyUncacheFiberNode); + } +} + +function appendInitialChild(parentInstance, child) { + parentInstance._children.push(child); +} + +function createInstance( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + var tag = allocateTag(); + var viewConfig = getViewConfigForType(type); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); + } + } + } + + var updatePayload = create(props, viewConfig.validAttributes); + + ReactNativePrivateInterface.UIManager.createView( + tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload // props + ); + + var component = new ReactNativeFiberHostComponent(tag, viewConfig); + + precacheFiberNode(internalInstanceHandle, tag); + updateFiberProps(tag, props); + + // Not sure how to avoid this cast. Flow is okay if the component is defined + // in the same file but if it's external it can't see the types. + return component; +} + +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + (function() { + if (!hostContext.isInAParentText) { + throw ReactError( + "Text strings must be rendered within a component." + ); + } + })(); + + var tag = allocateTag(); + + ReactNativePrivateInterface.UIManager.createView( + tag, // reactTag + "RCTRawText", // viewName + rootContainerInstance, // rootTag + { text: text } // props + ); + + precacheFiberNode(internalInstanceHandle, tag); + + return tag; +} + +function finalizeInitialChildren( + parentInstance, + type, + props, + rootContainerInstance, + hostContext +) { + // Don't send a no-op message over the bridge. + if (parentInstance._children.length === 0) { + return false; + } + + // Map from child objects to native tags. + // Either way we need to pass a copy of the Array to prevent it from being frozen. + var nativeTags = parentInstance._children.map(function(child) { + return typeof child === "number" + ? child // Leaf node (eg text) + : child._nativeTag; + }); + + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, // containerTag + nativeTags // reactTags + ); + + return false; +} + +function getRootHostContext(rootContainerInstance) { + return { isInAParentText: false }; +} + +function getChildHostContext(parentHostContext, type, rootContainerInstance) { + var prevIsInAParentText = parentHostContext.isInAParentText; + var isInAParentText = + type === "AndroidTextInput" || // Android + type === "RCTMultilineTextInputView" || // iOS + type === "RCTSinglelineTextInputView" || // iOS + type === "RCTText" || + type === "RCTVirtualText"; + + if (prevIsInAParentText !== isInAParentText) { + return { isInAParentText: isInAParentText }; + } else { + return parentHostContext; + } +} + +function getChildHostContextForEventComponent(parentHostContext) { + // TODO: add getChildHostContextForEventComponent implementation + return parentHostContext; +} + +function getChildHostContextForEventTarget(parentHostContext, type) { + // TODO: add getChildHostContextForEventTarget implementation + return parentHostContext; +} + +function getPublicInstance(instance) { + return instance; +} + +function prepareForCommit(containerInfo) { + // Noop +} + +function prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + hostContext +) { + return UPDATE_SIGNAL; +} + +function resetAfterCommit(containerInfo) { + // Noop +} + +var isPrimaryRenderer = true; + +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; + +function shouldDeprioritizeSubtree(type, props) { + return false; +} + +function shouldSetTextContent(type, props) { + // TODO (bvaughn) Revisit this decision. + // Always returning false simplifies the createInstance() implementation, + // But creates an additional child Fiber for raw text children. + // No additional native views are created though. + // It's not clear to me which is better so I'm deferring for now. + // More context @ github.com/facebook/react/pull/8560#discussion_r92111303 + return false; +} + +// ------------------- +// Mutation +// ------------------- + +var supportsMutation = true; + +function appendChild(parentInstance, child) { + var childTag = typeof child === "number" ? child : child._nativeTag; + var children = parentInstance._children; + var index = children.indexOf(child); + + if (index >= 0) { + children.splice(index, 1); + children.push(child); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerTag + [index], // moveFromIndices + [children.length - 1], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] // removeAtIndices + ); + } else { + children.push(child); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerTag + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [children.length - 1], // addAtIndices + [] // removeAtIndices + ); + } +} + +function appendChildToContainer(parentInstance, child) { + var childTag = typeof child === "number" ? child : child._nativeTag; + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance, // containerTag + [childTag] // reactTags + ); +} + +function commitTextUpdate(textInstance, oldText, newText) { + ReactNativePrivateInterface.UIManager.updateView( + textInstance, // reactTag + "RCTRawText", // viewName + { text: newText } // props + ); +} + +function commitUpdate( + instance, + updatePayloadTODO, + type, + oldProps, + newProps, + internalInstanceHandle +) { + var viewConfig = instance.viewConfig; + + updateFiberProps(instance._nativeTag, newProps); + + var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, // reactTag + viewConfig.uiViewClassName, // viewName + updatePayload // props + ); + } +} + +function insertBefore(parentInstance, child, beforeChild) { + var children = parentInstance._children; + var index = children.indexOf(child); + + // Move existing child or add new child? + if (index >= 0) { + children.splice(index, 1); + var beforeChildIndex = children.indexOf(beforeChild); + children.splice(beforeChildIndex, 0, child); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [index], // moveFromIndices + [beforeChildIndex], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] // removeAtIndices + ); + } else { + var _beforeChildIndex = children.indexOf(beforeChild); + children.splice(_beforeChildIndex, 0, child); + + var childTag = typeof child === "number" ? child : child._nativeTag; + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [_beforeChildIndex], // addAtIndices + [] // removeAtIndices + ); + } +} + +function insertInContainerBefore(parentInstance, child, beforeChild) { + // TODO (bvaughn): Remove this check when... + // We create a wrapper object for the container in ReactNative render() + // Or we refactor to remove wrapper objects entirely. + // For more info on pros/cons see PR #8560 description. + (function() { + if (!(typeof parentInstance !== "number")) { + throw ReactError("Container does not support insertBefore operation"); + } + })(); +} + +function removeChild(parentInstance, child) { + recursivelyUncacheFiberNode(child); + var children = parentInstance._children; + var index = children.indexOf(child); + + children.splice(index, 1); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [index] // removeAtIndices + ); +} + +function removeChildFromContainer(parentInstance, child) { + recursivelyUncacheFiberNode(child); + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [0] // removeAtIndices + ); +} + +function resetTextContent(instance) { + // Noop +} + +function hideInstance(instance) { + var viewConfig = instance.viewConfig; + var updatePayload = create( + { style: { display: "none" } }, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); +} + +function hideTextInstance(textInstance) { + throw new Error("Not yet implemented."); +} + +function unhideInstance(instance, props) { + var viewConfig = instance.viewConfig; + var updatePayload = diff( + Object.assign({}, props, { style: [props.style, { display: "none" }] }), + props, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); +} + +function unhideTextInstance(textInstance, text) { + throw new Error("Not yet implemented."); +} + +function mountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function updateEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function unmountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function getEventTargetChildElement(type, props) { + throw new Error("Not yet implemented."); +} + +function handleEventTarget( + type, + props, + rootContainerInstance, + internalInstanceHandle +) { + throw new Error("Not yet implemented."); +} + +function commitEventTarget(type, props, instance, parentInstance) { + throw new Error("Not yet implemented."); +} + +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; + +var describeComponentFrame = function(name, source, ownerName) { + var sourceInfo = ""; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ""); + { + // In DEV, include code for a common special case: + // prefer "folder/index.js" instead of just "index.js". + if (/^index\./.test(fileName)) { + var match = path.match(BEFORE_SLASH_RE); + if (match) { + var pathBeforeSlash = match[1]; + if (pathBeforeSlash) { + var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); + fileName = folderName + "/" + fileName; + } + } + } + } + sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; + } else if (ownerName) { + sourceInfo = " (created by " + ownerName + ")"; + } + return "\n in " + (name || "Unknown") + sourceInfo; +}; + +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + +function describeFiber(fiber) { + switch (fiber.tag) { + case HostRoot: + case HostPortal: + case HostText: + case Fragment: + case ContextProvider: + case ContextConsumer: + return ""; + default: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber.type); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner.type); + } + return describeComponentFrame(name, source, ownerName); + } +} + +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + node = node.return; + } while (node); + return info; +} + +var current = null; +var phase = null; + +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; + } + var owner = current._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner.type); + } + } + return null; +} + +function getCurrentFiberStackInDev() { + { + if (current === null) { + return ""; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackByFiberInDevAndProd(current); + } + return ""; +} + +function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + phase = null; + } +} + +function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackInDev; + current = fiber; + phase = null; + } +} + +function setCurrentPhase(lifeCyclePhase) { + { + phase = lifeCyclePhase; + } +} + +// Prefix measurements so that it's possible to filter them. +// Longer prefixes are hard to read in DevTools. +var reactEmoji = "\u269B"; +var warningEmoji = "\u26D4"; +var supportsUserTiming = + typeof performance !== "undefined" && + typeof performance.mark === "function" && + typeof performance.clearMarks === "function" && + typeof performance.measure === "function" && + typeof performance.clearMeasures === "function"; + +// Keep track of current fiber so that we know the path to unwind on pause. +// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? +var currentFiber = null; +// If we're in the middle of user code, which fiber and method is it? +// Reusing `currentFiber` would be confusing for this because user code fiber +// can change during commit phase too, but we don't need to unwind it (since +// lifecycles in the commit phase don't resemble a tree). +var currentPhase = null; +var currentPhaseFiber = null; +// Did lifecycle hook schedule an update? This is often a performance problem, +// so we will keep track of it, and include it in the report. +// Track commits caused by cascading updates. +var isCommitting = false; +var hasScheduledUpdateInCurrentCommit = false; +var hasScheduledUpdateInCurrentPhase = false; +var commitCountInCurrentWorkLoop = 0; +var effectCountInCurrentCommit = 0; +var isWaitingForCallback = false; +// During commits, we only show a measurement once per method name +// to avoid stretch the commit phase with measurement overhead. +var labelsInCurrentCommit = new Set(); + +var formatMarkName = function(markName) { + return reactEmoji + " " + markName; +}; + +var formatLabel = function(label, warning) { + var prefix = warning ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning ? " Warning: " + warning : ""; + return "" + prefix + label + suffix; +}; + +var beginMark = function(markName) { + performance.mark(formatMarkName(markName)); +}; + +var clearMark = function(markName) { + performance.clearMarks(formatMarkName(markName)); +}; + +var endMark = function(label, markName, warning) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning); + try { + performance.measure(formattedLabel, formattedMarkName); + } catch (err) {} + // If previous mark was missing for some reason, this will throw. + // This could only happen if React crashed in an unexpected place earlier. + // Don't pile on with more errors. + + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); +}; + +var getFiberMarkName = function(label, debugID) { + return label + " (#" + debugID + ")"; +}; + +var getFiberLabel = function(componentName, isMounted, phase) { + if (phase === null) { + // These are composite component total time measurements. + return componentName + " [" + (isMounted ? "update" : "mount") + "]"; + } else { + // Composite component methods. + return componentName + "." + phase; + } +}; + +var beginFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + + if (isCommitting && labelsInCurrentCommit.has(label)) { + // During the commit phase, we don't show duplicate labels because + // there is a fixed overhead for every measurement, and we don't + // want to stretch the commit phase beyond necessary. + return false; + } + labelsInCurrentCommit.add(label); + + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; +}; + +var clearFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + clearMark(markName); +}; + +var endFiberMark = function(fiber, phase, warning) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + endMark(label, markName, warning); +}; + +var shouldIgnoreFiber = function(fiber) { + // Host components should be skipped in the timeline. + // We could check typeof fiber.type, but does this work with RN? + switch (fiber.tag) { + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case Fragment: + case ContextProvider: + case ContextConsumer: + case Mode: + return true; + default: + return false; + } +}; + +var clearPendingPhaseMeasurement = function() { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; + +var pauseTimers = function() { + // Stops all currently active measurements so that they can be resumed + // if we continue in a later deferred loop from the same unit of work. + var fiber = currentFiber; + while (fiber) { + if (fiber._debugIsCurrentlyTiming) { + endFiberMark(fiber, null, null); + } + fiber = fiber.return; + } +}; + +var resumeTimersRecursively = function(fiber) { + if (fiber.return !== null) { + resumeTimersRecursively(fiber.return); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } +}; + +var resumeTimers = function() { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; + +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} + +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; + } + if ( + currentPhase !== null && + currentPhase !== "componentWillMount" && + currentPhase !== "componentWillReceiveProps" + ) { + hasScheduledUpdateInCurrentPhase = true; + } + } +} + +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark("(Waiting for async callback...)"); + } + } +} + +function stopRequestCallbackTimer(didExpire) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning = didExpire + ? "Update expired; will flush synchronously" + : null; + endMark( + "(Waiting for async callback...)", + "(Waiting for async callback...)", + warning + ); + } + } +} + +function startWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, this is the fiber to unwind from. + currentFiber = fiber; + if (!beginFiberMark(fiber, null)) { + return; + } + fiber._debugIsCurrentlyTiming = true; + } +} + +function cancelWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // Remember we shouldn't complete measurement for this fiber. + // Otherwise flamechart will be deep even for small updates. + fiber._debugIsCurrentlyTiming = false; + clearFiberMark(fiber, null); + } +} + +function stopWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + endFiberMark(fiber, null, null); + } +} + +function stopFailedWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + var warning = + fiber.tag === SuspenseComponent || + fiber.tag === DehydratedSuspenseComponent + ? "Rendering was suspended" + : "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning); + } +} + +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; + } + currentPhaseFiber = fiber; + currentPhase = phase; + } +} + +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + if (currentPhase !== null && currentPhaseFiber !== null) { + var warning = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning); + } + currentPhase = null; + currentPhaseFiber = null; + } +} + +function startWorkLoopTimer(nextUnitOfWork) { + if (enableUserTimingAPI) { + currentFiber = nextUnitOfWork; + if (!supportsUserTiming) { + return; + } + commitCountInCurrentWorkLoop = 0; + // This is top level call. + // Any other measurements are performed within. + beginMark("(React Tree Reconciliation)"); + // Resume any measurements that were in progress during the last loop. + resumeTimers(); + } +} + +function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var warning = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy.type) || "Unknown"; + warning = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning = "There were cascading updates"; + } + commitCountInCurrentWorkLoop = 0; + var label = didCompleteRoot + ? "(React Tree Reconciliation: Completed Root)" + : "(React Tree Reconciliation: Yielded)"; + // Pause any measurements until the next loop. + pauseTimers(); + endMark(label, "(React Tree Reconciliation)", warning); + } +} + +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark("(Committing Changes)"); + } +} + +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + + var warning = null; + if (hasScheduledUpdateInCurrentCommit) { + warning = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning = "Caused by a cascading update in earlier commit"; + } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark("(Committing Changes)", "(Committing Changes)", warning); + } +} + +function startCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Snapshot Effects)"); + } +} + +function stopCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Snapshot Effects: " + count + " Total)", + "(Committing Snapshot Effects)", + null + ); + } +} + +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Host Effects)"); + } +} + +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Host Effects: " + count + " Total)", + "(Committing Host Effects)", + null + ); + } +} + +function startCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Calling Lifecycle Methods)"); + } +} + +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Calling Lifecycle Methods: " + count + " Total)", + "(Calling Lifecycle Methods)", + null + ); + } +} + +var valueStack = []; + +var fiberStack = void 0; + +{ + fiberStack = []; +} + +var index = -1; + +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} + +function pop(cursor, fiber) { + if (index < 0) { + { + warningWithoutStack$1(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warningWithoutStack$1(false, "Unexpected Fiber popped."); + } + } + + cursor.current = valueStack[index]; + + valueStack[index] = null; + + { + fiberStack[index] = null; + } + + index--; +} + +function push(cursor, value, fiber) { + index++; + + valueStack[index] = cursor.current; + + { + fiberStack[index] = fiber; + } + + cursor.current = value; +} + +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var emptyContextObject = {}; +{ + Object.freeze(emptyContextObject); +} + +// A cursor to the current merged context object on the stack. +var contextStackCursor = createCursor(emptyContextObject); +// A cursor to a boolean indicating whether the context has changed. +var didPerformWorkStackCursor = createCursor(false); +// Keep track of the previous context object that was on the stack. +// We use this to get access to the parent context after we have already +// pushed the next context provider, and now need to merge their contexts. +var previousContext = emptyContextObject; + +function getUnmaskedContext( + workInProgress, + Component, + didPushOwnContextIfProvider +) { + if (didPushOwnContextIfProvider && isContextProvider(Component)) { + // If the fiber is a context provider itself, when we read its context + // we may have already pushed its own child context on the stack. A context + // provider should not "see" its own child context. Therefore we read the + // previous (parent) context instead for a context provider. + return previousContext; + } + return contextStackCursor.current; +} + +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; +} + +function getMaskedContext(workInProgress, unmaskedContext) { + var type = workInProgress.type; + var contextTypes = type.contextTypes; + if (!contextTypes) { + return emptyContextObject; + } + + // Avoid recreating masked context unless unmasked context has changed. + // Failing to do this will result in unnecessary calls to componentWillReceiveProps. + // This may trigger infinite loops if componentWillReceiveProps calls setState. + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) { + return instance.__reactInternalMemoizedMaskedChildContext; + } + + var context = {}; + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } + + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + getCurrentFiberStackInDev + ); + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // Context is created before the class component is instantiated so check for instance. + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return context; +} + +function hasContextChanged() { + return didPerformWorkStackCursor.current; +} + +function isContextProvider(type) { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; +} + +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function pushTopLevelContextObject(fiber, context, didChange) { + (function() { + if (!(contextStackCursor.current === emptyContextObject)) { + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} + +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = type.childContextTypes; + + // TODO (bvaughn) Replace this behavior with an invariant() in the future. + // It has only been added in Fiber to match the (unintentional) behavior in Stack. + if (typeof instance.getChildContext !== "function") { + { + var componentName = getComponentName(type) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warningWithoutStack$1( + false, + "%s.childContextTypes is specified but there is no getChildContext() method " + + "on the instance. You can either define getChildContext() on %s or remove " + + "childContextTypes from it.", + componentName, + componentName + ); + } + } + return parentContext; + } + + var childContext = void 0; + { + setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + setCurrentPhase(null); + } + for (var contextKey in childContext) { + (function() { + if (!(contextKey in childContextTypes)) { + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + } + })(); + } + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + childContextTypes, + childContext, + "child context", + name, + // In practice, there is one case in which we won't get a stack. It's when + // somebody calls unstable_renderSubtreeIntoContainer() and we process + // context from the parent component instance. The stack will be missing + // because it's outside of the reconciliation, and so the pointer has not + // been set. This is rare and doesn't matter. We'll also remove that API. + getCurrentFiberStackInDev + ); + } + + return Object.assign({}, parentContext, childContext); +} + +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + // We push the context as early as possible to ensure stack integrity. + // If the instance does not exist yet, we will push null at first, + // and replace it on the stack later when invalidating the context. + var memoizedMergedChildContext = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + + // Remember the parent context so we can merge with it later. + // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. + previousContext = contextStackCursor.current; + push(contextStackCursor, memoizedMergedChildContext, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + + return true; +} + +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + (function() { + if (!instance) { + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + if (didChange) { + // Merge parent and own context. + // Skip this if we're not updating due to sCU. + // This avoids unnecessarily recomputing memoized values. + var mergedContext = processChildContext( + workInProgress, + type, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + + // Replace the old (or empty) context with the new one. + // It is important to unwind the context in the reverse order. + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + // Now push the new context and mark that it has changed. + push(contextStackCursor, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } +} + +function findCurrentUnmaskedContext(fiber) { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + (function() { + if (!(isFiberMounted(fiber) && fiber.tag === ClassComponent)) { + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + var node = fiber; + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; + case ClassComponent: { + var Component = node.type; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + break; + } + } + node = node.return; + } while (node !== null); + (function() { + { + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +var hasLoggedError = false; + +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) { + if (true && !hasLoggedError) { + hasLoggedError = true; + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s", + err + ); + } + } + }; +} + +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; + +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; + } + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; + } + if (!hook.supportsFiber) { + { + warningWithoutStack$1( + false, + "The installed version of React DevTools is too old and will not work " + + "with the current version of React. Please update React DevTools. " + + "https://fb.me/react-devtools" + ); + } + // DevTools exists, even though it doesn't support Fiber. + return true; + } + try { + var rendererID = hook.inject(internals); + // We have successfully injected, so now it is safe to set up hooks. + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + { + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s.", + err + ); + } + } + // DevTools exists + return true; +} + +function onCommitRoot(root) { + if (typeof onCommitFiberRoot === "function") { + onCommitFiberRoot(root); + } +} + +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === "function") { + onCommitFiberUnmount(fiber); + } +} + +// Max 31 bit integer. The max integer size in V8 for 32-bit systems. +// Math.pow(2, 30) - 1 +// 0b111111111111111111111111111111 +var MAX_SIGNED_31_BIT_INT = 1073741823; + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority; +var Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback; +var Scheduler_cancelCallback = Scheduler.unstable_cancelCallback; +var Scheduler_shouldYield = Scheduler.unstable_shouldYield; +var Scheduler_now = Scheduler.unstable_now; +var Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel; +var Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority; +var Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; +var Scheduler_NormalPriority = Scheduler.unstable_NormalPriority; +var Scheduler_LowPriority = Scheduler.unstable_LowPriority; +var Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; + +if (enableSchedulerTracing) { + // Provide explicit error message when production+profiling bundle of e.g. + // react-dom is used with production (non-profiling) bundle of + // scheduler/tracing + (function() { + if ( + !( + tracing.__interactionsRef != null && + tracing.__interactionsRef.current != null + ) + ) { + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); + } + })(); +} + +var fakeCallbackNode = {}; + +// Except for NoPriority, these correspond to Scheduler priorities. We use +// ascending numbers so we can compare them like numbers. They start at 90 to +// avoid clashing with Scheduler's priorities. +var ImmediatePriority = 99; +var UserBlockingPriority = 98; +var NormalPriority = 97; +var LowPriority = 96; +var IdlePriority = 95; +// NoPriority is the absence of priority. Also React-only. + +var shouldYield = disableYielding + ? function() { + return false; + } // Never yield when `disableYielding` is on + : Scheduler_shouldYield; + +var immediateQueue = null; +var immediateQueueCallbackNode = null; +var isFlushingImmediate = false; +var initialTimeMs = Scheduler_now(); + +// If the initial timestamp is reasonably small, use Scheduler's `now` directly. +// This will be the case for modern browsers that support `performance.now`. In +// older browsers, Scheduler falls back to `Date.now`, which returns a Unix +// timestamp. In that case, subtract the module initialization time to simulate +// the behavior of performance.now and keep our times small enough to fit +// within 32 bits. +// TODO: Consider lifting this into Scheduler. +var now = + initialTimeMs < 10000 + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; + +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return ImmediatePriority; + case Scheduler_UserBlockingPriority: + return UserBlockingPriority; + case Scheduler_NormalPriority: + return NormalPriority; + case Scheduler_LowPriority: + return LowPriority; + case Scheduler_IdlePriority: + return IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case ImmediatePriority: + return Scheduler_ImmediatePriority; + case UserBlockingPriority: + return Scheduler_UserBlockingPriority; + case NormalPriority: + return Scheduler_NormalPriority; + case LowPriority: + return Scheduler_LowPriority; + case IdlePriority: + return Scheduler_IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function runWithPriority(reactPriorityLevel, fn) { + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(priorityLevel, fn); +} + +function scheduleCallback(reactPriorityLevel, callback, options) { + if (reactPriorityLevel === ImmediatePriority) { + // Push this callback into an internal queue. We'll flush these either in + // the next tick, or earlier if something calls `flushImmediateQueue`. + if (immediateQueue === null) { + immediateQueue = [callback]; + // Flush the queue in the next tick, at the earliest. + immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ); + } else { + // Push onto existing queue. Don't need to schedule a callback because + // we already scheduled one when we created the queue. + immediateQueue.push(callback); + } + return fakeCallbackNode; + } + // Otherwise pass through to Scheduler. + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(priorityLevel, callback, options); +} + +function cancelCallback(callbackNode) { + if (callbackNode !== fakeCallbackNode) { + Scheduler_cancelCallback(callbackNode); + } +} + +function flushImmediateQueue() { + if (immediateQueueCallbackNode !== null) { + Scheduler_cancelCallback(immediateQueueCallbackNode); + } + flushImmediateQueueImpl(); +} + +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && immediateQueue !== null) { + // Prevent re-entrancy. + isFlushingImmediate = true; + var i = 0; + try { + var _isSync = true; + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do { + callback = callback(_isSync); + } while (callback !== null); + } + immediateQueue = null; + } catch (error) { + // If something throws, leave the remaining callbacks on the queue. + if (immediateQueue !== null) { + immediateQueue = immediateQueue.slice(i + 1); + } + // Resume flushing in the next tick + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ); + throw error; + } finally { + isFlushingImmediate = false; + } + } +} + +var NoWork = 0; +var Never = 1; +var Sync = MAX_SIGNED_31_BIT_INT; + +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = MAX_SIGNED_31_BIT_INT - 1; + +// 1 unit of expiration time represents 10ms. +function msToExpirationTime(ms) { + // Always add an offset so that we don't clash with the magic number for NoWork. + return MAGIC_NUMBER_OFFSET - ((ms / UNIT_SIZE) | 0); +} + +function expirationTimeToMs(expirationTime) { + return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; +} + +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ( + MAGIC_NUMBER_OFFSET - + ceiling( + MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ) + ); +} + +// TODO: This corresponds to Scheduler's NormalPriority, not LowPriority. Update +// the names to reflect. +var LOW_PRIORITY_EXPIRATION = 5000; +var LOW_PRIORITY_BATCH_SIZE = 250; + +function computeAsyncExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + LOW_PRIORITY_EXPIRATION, + LOW_PRIORITY_BATCH_SIZE + ); +} + +// Same as computeAsyncExpiration but without the bucketing logic. This is +// used to compute timestamps instead of actual expiration times. +function computeAsyncExpirationNoBucket(currentTime) { + return currentTime - LOW_PRIORITY_EXPIRATION / UNIT_SIZE; +} + +// We intentionally set a higher expiration time for interactive updates in +// dev than in production. +// +// If the main thread is being blocked so long that you hit the expiration, +// it's a problem that could be solved with better scheduling. +// +// People will be more likely to notice this and fix it with the long +// expiration time in development. +// +// In production we opt for better UX at the risk of masking scheduling +// problems, by expiring fast. +var HIGH_PRIORITY_EXPIRATION = 500; +var HIGH_PRIORITY_BATCH_SIZE = 100; + +function computeInteractiveExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + HIGH_PRIORITY_EXPIRATION, + HIGH_PRIORITY_BATCH_SIZE + ); +} + +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (expirationTime === Sync) { + return ImmediatePriority; + } + if (expirationTime === Never) { + return IdlePriority; + } + var msUntil = + expirationTimeToMs(expirationTime) - expirationTimeToMs(currentTime); + if (msUntil <= 0) { + return ImmediatePriority; + } + if (msUntil <= HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE) { + return UserBlockingPriority; + } + if (msUntil <= LOW_PRIORITY_EXPIRATION + LOW_PRIORITY_BATCH_SIZE) { + return NormalPriority; + } + + // TODO: Handle LowPriority + + // Assume anything lower has idle priority + return IdlePriority; +} + +var NoContext = 0; +var ConcurrentMode = 1; +var StrictMode = 2; +var ProfileMode = 4; + +var hasBadMapPolyfill = void 0; + +{ + hasBadMapPolyfill = false; + try { + var nonExtensibleObject = Object.preventExtensions({}); + var testMap = new Map([[nonExtensibleObject, null]]); + var testSet = new Set([nonExtensibleObject]); + // This is necessary for Rollup to not consider these unused. + // https://github.com/rollup/rollup/issues/1771 + // TODO: we can remove these if Rollup fixes the bug. + testMap.set(0, 0); + testSet.add(0); + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } +} + +// A Fiber is work on a Component that needs to be done or was done. There can +// be more than one per component. + +var debugCounter = void 0; + +{ + debugCounter = 1; +} + +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; + + // Fiber + this.return = null; + this.child = null; + this.sibling = null; + this.index = 0; + + this.ref = null; + + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; + this.contextDependencies = null; + + this.mode = mode; + + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; + + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + this.childExpirationTime = NoWork; + + this.alternate = null; + + if (enableProfilerTimer) { + // Note: The following is done to avoid a v8 performance cliff. + // + // Initializing the fields below to smis and later updating them with + // double values will cause Fibers to end up having separate shapes. + // This behavior/bug has something to do with Object.preventExtension(). + // Fortunately this only impacts DEV builds. + // Unfortunately it makes React unusably slow for some applications. + // To work around this, initialize the fields below with doubles. + // + // Learn more about this here: + // https://github.com/facebook/react/issues/14365 + // https://bugs.chromium.org/p/v8/issues/detail?id=8538 + this.actualDuration = Number.NaN; + this.actualStartTime = Number.NaN; + this.selfBaseDuration = Number.NaN; + this.treeBaseDuration = Number.NaN; + + // It's okay to replace the initial doubles with smis after initialization. + // This won't trigger the performance cliff mentioned above, + // and it simplifies other profiler code (including DevTools). + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + this._debugHookTypes = null; + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); + } + } +} + +// This is a constructor function, rather than a POJO constructor, still +// please ensure we do the following: +// 1) Nobody should add any instance methods on this. Instance methods can be +// more difficult to predict when they get optimized and they are almost +// never inlined properly in static compilers. +// 2) Nobody should rely on `instanceof Fiber` for type testing. We should +// always know when it is a fiber. +// 3) We might want to experiment with using numeric keys since they are easier +// to optimize in a non-JIT environment. +// 4) We can easily go from a constructor to a createFiber object literal if that +// is faster. +// 5) It should be easy to port this to a C struct and keep a C implementation +// compatible. +var createFiber = function(tag, pendingProps, key, mode) { + // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +}; + +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} + +function isSimpleFunctionComponent(type) { + return ( + typeof type === "function" && + !shouldConstruct(type) && + type.defaultProps === undefined + ); +} + +function resolveLazyComponentTag(Component) { + if (typeof Component === "function") { + return shouldConstruct(Component) ? ClassComponent : FunctionComponent; + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + return ForwardRef; + } + if ($$typeof === REACT_MEMO_TYPE) { + return MemoComponent; + } + } + return IndeterminateComponent; +} + +// This is used to create an alternate fiber to do work on. +function createWorkInProgress(current, pendingProps, expirationTime) { + var workInProgress = current.alternate; + if (workInProgress === null) { + // We use a double buffering pooling technique because we know that we'll + // only ever need at most two versions of a tree. We pool the "other" unused + // node that we're free to reuse. This is lazily created to avoid allocating + // extra objects for things that are never updated. It also allow us to + // reclaim the extra memory if needed. + workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + ); + workInProgress.elementType = current.elementType; + workInProgress.type = current.type; + workInProgress.stateNode = current.stateNode; + + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } + + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; + + // We already have an alternate. + // Reset the effect tag. + workInProgress.effectTag = NoEffect; + + // The effect list is no longer valid. + workInProgress.nextEffect = null; + workInProgress.firstEffect = null; + workInProgress.lastEffect = null; + + if (enableProfilerTimer) { + // We intentionally reset, rather than copy, actualDuration & actualStartTime. + // This prevents time from endlessly accumulating in new commits. + // This has the downside of resetting values for different priority renders, + // But works for yielding (the common case) and should support resuming. + workInProgress.actualDuration = 0; + workInProgress.actualStartTime = -1; + } + } + + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + if (enableProfilerTimer) { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + return workInProgress; +} + +function createHostRootFiber(isConcurrent) { + var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; + + if (enableProfilerTimer && isDevToolsPresent) { + // Always collect profile timings when DevTools are present. + // This enables DevTools to start capturing timing at any point– + // Without some nodes in the tree having empty base times. + mode |= ProfileMode; + } + + return createFiber(HostRoot, null, null, mode); +} + +function createFiberFromTypeAndProps( + type, // React$ElementType + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiber = void 0; + + var fiberTag = IndeterminateComponent; + // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + var resolvedType = type; + if (typeof type === "function") { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; + } + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | ConcurrentMode | StrictMode, + expirationTime, + key + ); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | StrictMode, + expirationTime, + key + ); + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, expirationTime, key); + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, expirationTime, key); + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break getTag; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break getTag; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break getTag; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; + case REACT_EVENT_COMPONENT_TYPE: + if (enableEventAPI) { + return createFiberFromEventComponent( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + case REACT_EVENT_TARGET_TYPE: + if (enableEventAPI) { + return createFiberFromEventTarget( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + } + } + var info = ""; + { + if ( + type === undefined || + (typeof type === "object" && + type !== null && + Object.keys(type).length === 0) + ) { + info += + " You likely forgot to export your component from the file " + + "it's defined in, or you might have mixed up default and " + + "named imports."; + } + var ownerName = owner ? getComponentName(owner.type) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } + (function() { + { + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (type == null ? type : typeof type) + + "." + + info + ); + } + })(); + } + } + } + + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; + } + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime + ); + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; + } + return fiber; +} + +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventComponent( + eventComponent, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventComponent, pendingProps, key, mode); + fiber.elementType = eventComponent; + fiber.type = eventComponent; + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventTarget( + eventTarget, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventTarget, pendingProps, key, mode); + fiber.elementType = eventTarget; + fiber.type = eventTarget; + fiber.expirationTime = expirationTime; + // Store latest props + fiber.stateNode = { + props: pendingProps + }; + return fiber; +} + +function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { + { + if ( + typeof pendingProps.id !== "string" || + typeof pendingProps.onRender !== "function" + ) { + warningWithoutStack$1( + false, + 'Profiler must specify an "id" string and "onRender" function as props' + ); + } + } + + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + // TODO: The Profiler fiber shouldn't have a type. It has a tag. + fiber.elementType = REACT_PROFILER_TYPE; + fiber.type = REACT_PROFILER_TYPE; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(Mode, pendingProps, key, mode); + + // TODO: The Mode fiber shouldn't have a type. It has a tag. + var type = + (mode & ConcurrentMode) === NoContext + ? REACT_STRICT_MODE_TYPE + : REACT_CONCURRENT_MODE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + + // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. + var type = REACT_SUSPENSE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoContext); + // TODO: These should not need a type. + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + return fiber; +} + +function createFiberFromPortal(portal, mode, expirationTime) { + var pendingProps = portal.children !== null ? portal.children : []; + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); + fiber.expirationTime = expirationTime; + fiber.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, // Used by persistent updates + implementation: portal.implementation + }; + return fiber; +} + +// Used for stashing WIP properties to replay failed work in DEV. +function assignFiberPropertiesInDEV(target, source) { + if (target === null) { + // This Fiber's initial properties will always be overwritten. + // We only use a Fiber to ensure the same hidden class so DEV isn't slow. + target = createFiber(IndeterminateComponent, null, null, NoContext); + } + + // This is intentionally written as a list of all properties. + // We tried to use Object.assign() instead but this is called in + // the hottest path, and Object.assign() was too slow: + // https://github.com/facebook/react/issues/12502 + // This code is DEV-only so size is not a concern. + + target.tag = source.tag; + target.key = source.key; + target.elementType = source.elementType; + target.type = source.type; + target.stateNode = source.stateNode; + target.return = source.return; + target.child = source.child; + target.sibling = source.sibling; + target.index = source.index; + target.ref = source.ref; + target.pendingProps = source.pendingProps; + target.memoizedProps = source.memoizedProps; + target.updateQueue = source.updateQueue; + target.memoizedState = source.memoizedState; + target.contextDependencies = source.contextDependencies; + target.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.childExpirationTime = source.childExpirationTime; + target.alternate = source.alternate; + if (enableProfilerTimer) { + target.actualDuration = source.actualDuration; + target.actualStartTime = source.actualStartTime; + target.selfBaseDuration = source.selfBaseDuration; + target.treeBaseDuration = source.treeBaseDuration; + } + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + target._debugHookTypes = source._debugHookTypes; + return target; +} + +// TODO: This should be lifted into the renderer. + +// The following attributes are only used by interaction tracing builds. +// They enable interactions to be associated with their async work, +// And expose interaction metadata to the React DevTools Profiler plugin. +// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. + +// Exported FiberRoot type includes all properties, +// To avoid requiring potentially error-prone :any casts throughout the project. +// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). +// The types are defined separately within this file to ensure they stay in sync. +// (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) + +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pendingChildren = null; + this.pingCache = null; + this.pendingCommitExpirationTime = NoWork; + this.finishedWork = null; + this.timeoutHandle = noTimeout; + this.context = null; + this.pendingContext = null; + this.hydrate = hydrate; + this.firstBatch = null; + this.callbackNode = null; + this.callbackExpirationTime = NoWork; + this.firstPendingTime = NoWork; + this.lastPendingTime = NoWork; + this.pingTime = NoWork; + + if (enableSchedulerTracing) { + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); + } +} + +function createFiberRoot(containerInfo, isConcurrent, hydrate) { + var root = new FiberRootNode(containerInfo, hydrate); + + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isConcurrent); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + + return root; +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warning = warningWithoutStack$1; + +{ + warning = function(condition, format) { + if (condition) { + return; + } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame.getStackAddendum(); + // eslint-disable-next-line react-internal/warning-and-invariant-args + + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + warningWithoutStack$1.apply( + undefined, + [false, format + "%s"].concat(args, [stack]) + ); + }; +} + +var warning$1 = warning; + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x, y) { + return ( + (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare + ); +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA, objB) { + if (is(objA, objB)) { + return true; + } + + if ( + typeof objA !== "object" || + objA === null || + typeof objB !== "object" || + objB === null + ) { + return false; + } + + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + for (var i = 0; i < keysA.length; i++) { + if ( + !hasOwnProperty.call(objB, keysA[i]) || + !is(objA[keysA[i]], objB[keysA[i]]) + ) { + return false; + } + } + + return true; +} + +/** + * Forked from fbjs/warning: + * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js + * + * Only change is we use console.warn instead of console.error, + * and do nothing when 'console' is not supported. + * This really simplifies the code. + * --- + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var lowPriorityWarning = function() {}; + +{ + var printWarning = function(format) { + for ( + var _len = arguments.length, + args = Array(_len > 1 ? _len - 1 : 0), + _key = 1; + _key < _len; + _key++ + ) { + args[_key - 1] = arguments[_key]; + } + + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + if (typeof console !== "undefined") { + console.warn(message); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} + }; + + lowPriorityWarning = function(condition, format) { + if (format === undefined) { + throw new Error( + "`lowPriorityWarning(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (!condition) { + for ( + var _len2 = arguments.length, + args = Array(_len2 > 2 ? _len2 - 2 : 0), + _key2 = 2; + _key2 < _len2; + _key2++ + ) { + args[_key2 - 2] = arguments[_key2]; + } + + printWarning.apply(undefined, [format].concat(args)); + } + }; +} + +var lowPriorityWarning$1 = lowPriorityWarning; + +var ReactStrictModeWarnings = { + discardPendingWarnings: function() {}, + flushPendingDeprecationWarnings: function() {}, + flushPendingUnsafeLifecycleWarnings: function() {}, + recordDeprecationWarnings: function(fiber, instance) {}, + recordUnsafeLifecycleWarnings: function(fiber, instance) {}, + recordLegacyContextWarning: function(fiber, instance) {}, + flushLegacyContextWarning: function() {} +}; + +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; + + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); + var pendingLegacyContextWarning = new Map(); + + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = new Set(); + var didWarnAboutLegacyContext = new Set(); + + var setToSortedString = function(set) { + var array = []; + set.forEach(function(value) { + array.push(value); + }); + return array.sort().join(", "); + }; + + ReactStrictModeWarnings.discardPendingWarnings = function() { + pendingComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUnsafeLifecycleWarnings = new Map(); + pendingLegacyContextWarning = new Map(); + }; + + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMessages = []; + + Object.keys(lifecycleWarningsMap).forEach(function(lifecycle) { + var lifecycleWarnings = lifecycleWarningsMap[lifecycle]; + if (lifecycleWarnings.length > 0) { + var componentNames = new Set(); + lifecycleWarnings.forEach(function(fiber) { + componentNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = setToSortedString(componentNames); + + lifecyclesWarningMessages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); + + if (lifecyclesWarningMessages.length > 0) { + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Unsafe lifecycle methods were found within a strict-mode tree:%s" + + "\n\n%s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + lifecyclesWarningMessages.join("\n\n") + ); + } + }); + + pendingUnsafeLifecycleWarnings = new Map(); + }; + + var findStrictRoot = function(fiber) { + var maybeStrictRoot = null; + + var node = fiber; + while (node !== null) { + if (node.mode & StrictMode) { + maybeStrictRoot = node; + } + node = node.return; + } + + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillMount is deprecated and will be removed in the next major version. " + + "Use componentDidMount instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillMount." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + sortedNames + ); + + pendingComponentWillMountWarnings = []; + } + + if (pendingComponentWillReceivePropsWarnings.length > 0) { + var _uniqueNames = new Set(); + pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { + _uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames = setToSortedString(_uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillReceiveProps is deprecated and will be removed in the next major version. " + + "Use static getDerivedStateFromProps instead." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames + ); + + pendingComponentWillReceivePropsWarnings = []; + } + + if (pendingComponentWillUpdateWarnings.length > 0) { + var _uniqueNames2 = new Set(); + pendingComponentWillUpdateWarnings.forEach(function(fiber) { + _uniqueNames2.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames2 = setToSortedString(_uniqueNames2); + + lowPriorityWarning$1( + false, + "componentWillUpdate is deprecated and will be removed in the next major version. " + + "Use componentDidUpdate instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillUpdate." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames2 + ); + + pendingComponentWillUpdateWarnings = []; + } + }; + + ReactStrictModeWarnings.recordDeprecationWarnings = function( + fiber, + instance + ) { + // Dedup strategy: Warn once per component. + if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { + return; + } + + // Don't warn about react-lifecycles-compat polyfilled components. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } + }; + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + // This is difficult to track any other way since component names + // are often vague and are likely to collide between 3rd party libraries. + // An expand property is probably okay to use here since it's DEV-only, + // and will only be set in the event of serious warnings. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } + + var warningsForRoot = void 0; + if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { + warningsForRoot = { + UNSAFE_componentWillMount: [], + UNSAFE_componentWillReceiveProps: [], + UNSAFE_componentWillUpdate: [] + }; + + pendingUnsafeLifecycleWarnings.set(strictRoot, warningsForRoot); + } else { + warningsForRoot = pendingUnsafeLifecycleWarnings.get(strictRoot); + } + + var unsafeLifecycles = []; + if ( + (typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + (typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true) || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + (typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + } + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); + } + }; + + ReactStrictModeWarnings.recordLegacyContextWarning = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } + + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } + warningsForRoot.push(fiber); + } + }; + + ReactStrictModeWarnings.flushLegacyContextWarning = function() { + pendingLegacyContextWarning.forEach(function(fiberArray, strictRoot) { + var uniqueNames = new Set(); + fiberArray.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Legacy context API has been detected within a strict-mode tree: %s" + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + sortedNames + ); + }); + }; +} + +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = Object.assign({}, baseProps); + var defaultProps = Component.defaultProps; + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; + } + } + return props; + } + return baseProps; +} + +function readLazyComponentType(lazyComponent) { + var status = lazyComponent._status; + var result = lazyComponent._result; + switch (status) { + case Resolved: { + var Component = result; + return Component; + } + case Rejected: { + var error = result; + throw error; + } + case Pending: { + var thenable = result; + throw thenable; + } + default: { + lazyComponent._status = Pending; + var ctor = lazyComponent._ctor; + var _thenable = ctor(); + _thenable.then( + function(moduleObject) { + if (lazyComponent._status === Pending) { + var defaultExport = moduleObject.default; + { + if (defaultExport === undefined) { + warning$1( + false, + "lazy: Expected the result of a dynamic import() call. " + + "Instead received: %s\n\nYour code should look like: \n " + + "const MyComponent = lazy(() => import('./MyComponent'))", + moduleObject + ); + } + } + lazyComponent._status = Resolved; + lazyComponent._result = defaultExport; + } + }, + function(error) { + if (lazyComponent._status === Pending) { + lazyComponent._status = Rejected; + lazyComponent._result = error; + } + } + ); + // Handle synchronous thenables. + switch (lazyComponent._status) { + case Resolved: + return lazyComponent._result; + case Rejected: + throw lazyComponent._result; + } + lazyComponent._result = _thenable; + throw _thenable; + } + } +} + +var valueCursor = createCursor(null); + +var rendererSigil = void 0; +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} + +var currentlyRenderingFiber = null; +var lastContextDependency = null; +var lastContextWithAllBitsObserved = null; + +var isDisallowedContextReadInDEV = false; + +function resetContextDependences() { + // This is called right before React yields execution, to ensure `readContext` + // cannot be called outside the render phase. + currentlyRenderingFiber = null; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + { + isDisallowedContextReadInDEV = false; + } +} + +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} + +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} + +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + + if (isPrimaryRenderer) { + push(valueCursor, context._currentValue, providerFiber); + + context._currentValue = nextValue; + { + !( + context._currentRenderer === undefined || + context._currentRenderer === null || + context._currentRenderer === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer = rendererSigil; + } + } else { + push(valueCursor, context._currentValue2, providerFiber); + + context._currentValue2 = nextValue; + { + !( + context._currentRenderer2 === undefined || + context._currentRenderer2 === null || + context._currentRenderer2 === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer2 = rendererSigil; + } + } +} + +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + + pop(valueCursor, providerFiber); + + var context = providerFiber.type._context; + if (isPrimaryRenderer) { + context._currentValue = currentValue; + } else { + context._currentValue2 = currentValue; + } +} + +function calculateChangedBits(context, newValue, oldValue) { + if (is(oldValue, newValue)) { + // No change + return 0; + } else { + var changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + + { + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning$1( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; + } + return changedBits | 0; + } +} + +function scheduleWorkOnParentPath(parent, renderExpirationTime) { + // Update the child expiration time of all the ancestors, including + // the alternates. + var node = parent; + while (node !== null) { + var alternate = node.alternate; + if (node.childExpirationTime < renderExpirationTime) { + node.childExpirationTime = renderExpirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; + } + node = node.return; + } +} + +function propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime +) { + var fiber = workInProgress.child; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } + while (fiber !== null) { + var nextFiber = void 0; + + // Visit this fiber. + var list = fiber.contextDependencies; + if (list !== null) { + nextFiber = fiber.child; + + var dependency = list.first; + while (dependency !== null) { + // Check if the context matches. + if ( + dependency.context === context && + (dependency.observedBits & changedBits) !== 0 + ) { + // Match! Schedule an update on this fiber. + + if (fiber.tag === ClassComponent) { + // Schedule a force update on the work-in-progress. + var update = createUpdate(renderExpirationTime); + update.tag = ForceUpdate; + // TODO: Because we don't have a work-in-progress, this will add the + // update to the current fiber, too, which means it will persist even if + // this render is thrown away. Since it's a race condition, not sure it's + // worth fixing. + enqueueUpdate(fiber, update); + } + + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var alternate = fiber.alternate; + if ( + alternate !== null && + alternate.expirationTime < renderExpirationTime + ) { + alternate.expirationTime = renderExpirationTime; + } + + scheduleWorkOnParentPath(fiber.return, renderExpirationTime); + + // Mark the expiration time on the list, too. + if (list.expirationTime < renderExpirationTime) { + list.expirationTime = renderExpirationTime; + } + + // Since we already found a match, we can stop traversing the + // dependency list. + break; + } + dependency = dependency.next; + } + } else if (fiber.tag === ContextProvider) { + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + } else if ( + enableSuspenseServerRenderer && + fiber.tag === DehydratedSuspenseComponent + ) { + // If a dehydrated suspense component is in this subtree, we don't know + // if it will have any context consumers in it. The best we can do is + // mark it as having updates on its children. + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var _alternate = fiber.alternate; + if ( + _alternate !== null && + _alternate.expirationTime < renderExpirationTime + ) { + _alternate.expirationTime = renderExpirationTime; + } + // This is intentionally passing this fiber as the parent + // because we want to schedule this fiber as having work + // on its children. We'll use the childExpirationTime on + // this fiber to indicate that a context has changed. + scheduleWorkOnParentPath(fiber, renderExpirationTime); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } + + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber.return = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } + var sibling = nextFiber.sibling; + if (sibling !== null) { + // Set the return pointer of the sibling to the work-in-progress fiber. + sibling.return = nextFiber.return; + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber.return; + } + } + fiber = nextFiber; + } +} + +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + + var currentDependencies = workInProgress.contextDependencies; + if ( + currentDependencies !== null && + currentDependencies.expirationTime >= renderExpirationTime + ) { + // Context list has a pending update. Mark that this fiber performed work. + markWorkInProgressReceivedUpdate(); + } + + // Reset the work-in-progress list + workInProgress.contextDependencies = null; +} + +function readContext(context, observedBits) { + { + // This warning would fire if you read context inside a Hook like useMemo. + // Unlike the class check below, it's not enforced in production for perf. + !!isDisallowedContextReadInDEV + ? warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ) + : void 0; + } + + if (lastContextWithAllBitsObserved === context) { + // Nothing to do. We already observe everything in this context. + } else if (observedBits === false || observedBits === 0) { + // Do not observe any updates. + } else { + var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. + if ( + typeof observedBits !== "number" || + observedBits === MAX_SIGNED_31_BIT_INT + ) { + // Observe all updates. + lastContextWithAllBitsObserved = context; + resolvedObservedBits = MAX_SIGNED_31_BIT_INT; + } else { + resolvedObservedBits = observedBits; + } + + var contextItem = { + context: context, + observedBits: resolvedObservedBits, + next: null + }; + + if (lastContextDependency === null) { + (function() { + if (!(currentlyRenderingFiber !== null)) { + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + } + })(); + + // This is the first dependency for this component. Create a new list. + lastContextDependency = contextItem; + currentlyRenderingFiber.contextDependencies = { + first: contextItem, + expirationTime: NoWork + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; + } + } + return isPrimaryRenderer ? context._currentValue : context._currentValue2; +} + +// UpdateQueue is a linked list of prioritized updates. +// +// Like fibers, update queues come in pairs: a current queue, which represents +// the visible state of the screen, and a work-in-progress queue, which can be +// mutated and processed asynchronously before it is committed — a form of +// double buffering. If a work-in-progress render is discarded before finishing, +// we create a new work-in-progress by cloning the current queue. +// +// Both queues share a persistent, singly-linked list structure. To schedule an +// update, we append it to the end of both queues. Each queue maintains a +// pointer to first update in the persistent list that hasn't been processed. +// The work-in-progress pointer always has a position equal to or greater than +// the current queue, since we always work on that one. The current queue's +// pointer is only updated during the commit phase, when we swap in the +// work-in-progress. +// +// For example: +// +// Current pointer: A - B - C - D - E - F +// Work-in-progress pointer: D - E - F +// ^ +// The work-in-progress queue has +// processed more updates than current. +// +// The reason we append to both queues is because otherwise we might drop +// updates without ever processing them. For example, if we only add updates to +// the work-in-progress queue, some updates could be lost whenever a work-in +// -progress render restarts by cloning from current. Similarly, if we only add +// updates to the current queue, the updates will be lost whenever an already +// in-progress queue commits and swaps with the current queue. However, by +// adding to both queues, we guarantee that the update will be part of the next +// work-in-progress. (And because the work-in-progress queue becomes the +// current queue once it commits, there's no danger of applying the same +// update twice.) +// +// Prioritization +// -------------- +// +// Updates are not sorted by priority, but by insertion; new updates are always +// appended to the end of the list. +// +// The priority is still important, though. When processing the update queue +// during the render phase, only the updates with sufficient priority are +// included in the result. If we skip an update because it has insufficient +// priority, it remains in the queue to be processed later, during a lower +// priority render. Crucially, all updates subsequent to a skipped update also +// remain in the queue *regardless of their priority*. That means high priority +// updates are sometimes processed twice, at two separate priorities. We also +// keep track of a base state, that represents the state before the first +// update in the queue is applied. +// +// For example: +// +// Given a base state of '', and the following queue of updates +// +// A1 - B2 - C1 - D2 +// +// where the number indicates the priority, and the update is applied to the +// previous state by appending a letter, React will process these updates as +// two separate renders, one per distinct priority level: +// +// First render, at priority 1: +// Base state: '' +// Updates: [A1, C1] +// Result state: 'AC' +// +// Second render, at priority 2: +// Base state: 'A' <- The base state does not include C1, +// because B2 was skipped. +// Updates: [B2, C1, D2] <- C1 was rebased on top of B2 +// Result state: 'ABCD' +// +// Because we process updates in insertion order, and rebase high priority +// updates when preceding updates are skipped, the final result is deterministic +// regardless of priority. Intermediate state may vary according to system +// resources, but the final state is always the same. + +var UpdateState = 0; +var ReplaceState = 1; +var ForceUpdate = 2; +var CaptureUpdate = 3; + +// Global state that is reset at the beginning of calling `processUpdateQueue`. +// It should only be read right after calling `processUpdateQueue`, via +// `checkHasForceUpdateAfterProcessing`. +var hasForceUpdate = false; + +var didWarnUpdateInsideUpdate = void 0; +var currentlyProcessingQueue = void 0; + +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} + +function createUpdateQueue(baseState) { + var queue = { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function cloneUpdateQueue(currentQueue) { + var queue = { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + + // TODO: With resuming, if we bail out and resuse the child tree, we should + // keep these effects. + firstCapturedUpdate: null, + lastCapturedUpdate: null, + + firstEffect: null, + lastEffect: null, + + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + + tag: UpdateState, + payload: null, + callback: null, + + next: null, + nextEffect: null + }; +} + +function appendUpdateToQueue(queue, update) { + // Append the update to the end of the list. + if (queue.lastUpdate === null) { + // Queue is empty + queue.firstUpdate = queue.lastUpdate = update; + } else { + queue.lastUpdate.next = update; + queue.lastUpdate = update; + } +} + +function enqueueUpdate(fiber, update) { + // Update queues are created lazily. + var alternate = fiber.alternate; + var queue1 = void 0; + var queue2 = void 0; + if (alternate === null) { + // There's only one fiber. + queue1 = fiber.updateQueue; + queue2 = null; + if (queue1 === null) { + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + } + } else { + // There are two owners. + queue1 = fiber.updateQueue; + queue2 = alternate.updateQueue; + if (queue1 === null) { + if (queue2 === null) { + // Neither fiber has an update queue. Create new ones. + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ); + } else { + // Only one fiber has an update queue. Clone to create a new one. + queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); + } + } else { + if (queue2 === null) { + // Only one fiber has an update queue. Clone to create a new one. + queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); + } else { + // Both owners have an update queue. + } + } + } + if (queue2 === null || queue1 === queue2) { + // There's only a single queue. + appendUpdateToQueue(queue1, update); + } else { + // There are two queues. We need to append the update to both queues, + // while accounting for the persistent structure of the list — we don't + // want the same update to be added multiple times. + if (queue1.lastUpdate === null || queue2.lastUpdate === null) { + // One of the queues is not empty. We must add the update to both queues. + appendUpdateToQueue(queue1, update); + appendUpdateToQueue(queue2, update); + } else { + // Both queues are non-empty. The last update is the same in both lists, + // because of structural sharing. So, only append to one of the lists. + appendUpdateToQueue(queue1, update); + // But we still need to update the `lastUpdate` pointer of queue2. + queue2.lastUpdate = update; + } + } + + { + if ( + fiber.tag === ClassComponent && + (currentlyProcessingQueue === queue1 || + (queue2 !== null && currentlyProcessingQueue === queue2)) && + !didWarnUpdateInsideUpdate + ) { + warningWithoutStack$1( + false, + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback." + ); + didWarnUpdateInsideUpdate = true; + } + } +} + +function enqueueCapturedUpdate(workInProgress, update) { + // Captured updates go into a separate list, and only on the work-in- + // progress queue. + var workInProgressQueue = workInProgress.updateQueue; + if (workInProgressQueue === null) { + workInProgressQueue = workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + ); + } else { + // TODO: I put this here rather than createWorkInProgress so that we don't + // clone the queue unnecessarily. There's probably a better way to + // structure this. + workInProgressQueue = ensureWorkInProgressQueueIsAClone( + workInProgress, + workInProgressQueue + ); + } + + // Append the update to the end of the list. + if (workInProgressQueue.lastCapturedUpdate === null) { + // This is the first render phase update + workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; + } else { + workInProgressQueue.lastCapturedUpdate.next = update; + workInProgressQueue.lastCapturedUpdate = update; + } +} + +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + if (current !== null) { + // If the work-in-progress queue is equal to the current queue, + // we need to clone it first. + if (queue === current.updateQueue) { + queue = workInProgress.updateQueue = cloneUpdateQueue(queue); + } + } + return queue; +} + +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var _payload = update.payload; + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload.call(instance, prevState, nextProps); + } + } + var nextState = _payload.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + return nextState; + } + // State object + return _payload; + } + case CaptureUpdate: { + workInProgress.effectTag = + (workInProgress.effectTag & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough + case UpdateState: { + var _payload2 = update.payload; + var partialState = void 0; + if (typeof _payload2 === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload2.call(instance, prevState, nextProps); + } + } + partialState = _payload2.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload2; + } + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } + // Merge the partial state and the previous state. + return Object.assign({}, prevState, partialState); + } + case ForceUpdate: { + hasForceUpdate = true; + return prevState; + } + } + return prevState; +} + +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = false; + + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + + { + currentlyProcessingQueue = queue; + } + + // These values may change as we process the queue. + var newBaseState = queue.baseState; + var newFirstUpdate = null; + var newExpirationTime = NoWork; + + // Iterate through the list of updates to compute the result. + var update = queue.firstUpdate; + var resultState = newBaseState; + while (update !== null) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstUpdate === null) { + // This is the first skipped update. It will be the first update in + // the new list. + newFirstUpdate = update; + // Since this is the first update that was skipped, the current result + // is the new base state. + newBaseState = resultState; + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < updateExpirationTime) { + newExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process it and compute a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback = update.callback; + if (_callback !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastEffect === null) { + queue.firstEffect = queue.lastEffect = update; + } else { + queue.lastEffect.nextEffect = update; + queue.lastEffect = update; + } + } + } + // Continue to the next update. + update = update.next; + } + + // Separately, iterate though the list of captured updates. + var newFirstCapturedUpdate = null; + update = queue.firstCapturedUpdate; + while (update !== null) { + var _updateExpirationTime = update.expirationTime; + if (_updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstCapturedUpdate === null) { + // This is the first skipped captured update. It will be the first + // update in the new list. + newFirstCapturedUpdate = update; + // If this is the first update that was skipped, the current result is + // the new base state. + if (newFirstUpdate === null) { + newBaseState = resultState; + } + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < _updateExpirationTime) { + newExpirationTime = _updateExpirationTime; + } + } else { + // This update does have sufficient priority. Process it and compute + // a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback2 = update.callback; + if (_callback2 !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastCapturedEffect === null) { + queue.firstCapturedEffect = queue.lastCapturedEffect = update; + } else { + queue.lastCapturedEffect.nextEffect = update; + queue.lastCapturedEffect = update; + } + } + } + update = update.next; + } + + if (newFirstUpdate === null) { + queue.lastUpdate = null; + } + if (newFirstCapturedUpdate === null) { + queue.lastCapturedUpdate = null; + } else { + workInProgress.effectTag |= Callback; + } + if (newFirstUpdate === null && newFirstCapturedUpdate === null) { + // We processed every update, without skipping. That means the new base + // state is the same as the result state. + newBaseState = resultState; + } + + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = newFirstCapturedUpdate; + + // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; + + { + currentlyProcessingQueue = null; + } +} + +function callCallback(callback, context) { + (function() { + if (!(typeof callback === "function")) { + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + callback + ); + } + })(); + callback.call(context); +} + +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} + +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} + +function commitUpdateQueue( + finishedWork, + finishedQueue, + instance, + renderExpirationTime +) { + // If the finished render included captured updates, and there are still + // lower priority updates left over, we need to keep the captured updates + // in the queue so that they are rebased and not dropped once we process the + // queue again at the lower priority. + if (finishedQueue.firstCapturedUpdate !== null) { + // Join the captured update list to the end of the normal list. + if (finishedQueue.lastUpdate !== null) { + finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; + finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; + } + // Clear the list of captured updates. + finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; + } + + // Commit the effects + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} + +function commitUpdateEffects(effect, instance) { + while (effect !== null) { + var _callback3 = effect.callback; + if (_callback3 !== null) { + effect.callback = null; + callCallback(_callback3, instance); + } + effect = effect.nextEffect; + } +} + +var fakeInternalInstance = {}; +var isArray$1 = Array.isArray; + +// React.Component uses a shared frozen object by default. +// We'll use it to determine whether we need to initialize legacy refs. +var emptyRefsObject = new React.Component().refs; + +var didWarnAboutStateAssignmentForComponent = void 0; +var didWarnAboutUninitializedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; +var didWarnAboutUndefinedDerivedState = void 0; +var warnOnUndefinedDerivedState = void 0; +var warnOnInvalidCallback = void 0; +var didWarnAboutDirectlyAssigningPropsToState = void 0; +var didWarnAboutContextTypeAndContextTypes = void 0; +var didWarnAboutInvalidateContextType = void 0; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutDirectlyAssigningPropsToState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutContextTypeAndContextTypes = new Set(); + didWarnAboutInvalidateContextType = new Set(); + + var didWarnOnInvalidCallback = new Set(); + + warnOnInvalidCallback = function(callback, callerName) { + if (callback === null || typeof callback === "function") { + return; + } + var key = callerName + "_" + callback; + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); + warningWithoutStack$1( + false, + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); + } + }; + + warnOnUndefinedDerivedState = function(type, partialState) { + if (partialState === undefined) { + var componentName = getComponentName(type) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warningWithoutStack$1( + false, + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName + ); + } + } + }; + + // This is so gross but it's at least non-critical and can be removed if + // it causes problems. This is meant to give a nicer error message for + // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, + // ...)) which otherwise throws a "_processChildContext is not a function" + // exception. + Object.defineProperty(fakeInternalInstance, "_processChildContext", { + enumerable: false, + value: function() { + (function() { + { + throw ReactError( + "_processChildContext is not available in React 16+. This likely means you have multiple copies of React and are attempting to nest a React 15 tree inside a React 16 tree using unstable_renderSubtreeIntoContainer, which isn't supported. Try to make sure you have only one copy of React (and ideally, switch to ReactDOM.createPortal)." + ); + } + })(); + } + }); + Object.freeze(fakeInternalInstance); +} + +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Invoke the function an extra time to help detect side-effects. + getDerivedStateFromProps(nextProps, prevState); + } + } + + var partialState = getDerivedStateFromProps(nextProps, prevState); + + { + warnOnUndefinedDerivedState(ctor, partialState); + } + // Merge the partial state and the previous state. + var memoizedState = + partialState === null || partialState === undefined + ? prevState + : Object.assign({}, prevState, partialState); + workInProgress.memoizedState = memoizedState; + + // Once the update queue is empty, persist the derived state onto the + // base state. + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && workInProgress.expirationTime === NoWork) { + updateQueue.baseState = memoizedState; + } +} + +var classComponentUpdater = { + isMounted: isMounted, + enqueueSetState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.payload = payload; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "setState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ReplaceState; + update.payload = payload; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "replaceState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueForceUpdate: function(inst, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ForceUpdate; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + } +}; + +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + var instance = workInProgress.stateNode; + if (typeof instance.shouldComponentUpdate === "function") { + startPhaseTimer(workInProgress, "shouldComponentUpdate"); + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + stopPhaseTimer(); + + { + !(shouldUpdate !== undefined) + ? warningWithoutStack$1( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(ctor) || "Component" + ) + : void 0; + } + + return shouldUpdate; + } + + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); + } + + return true; +} + +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; + { + var name = getComponentName(ctor) || "Component"; + var renderPresent = instance.render; + + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === "function") { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: you may have forgotten to define `render`.", + name + ); + } + } + + var noGetInitialStateOnES6 = + !instance.getInitialState || + instance.getInitialState.isReactClassApproved || + instance.state; + !noGetInitialStateOnES6 + ? warningWithoutStack$1( + false, + "getInitialState was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Did you mean to define a state property instead?", + name + ) + : void 0; + var noGetDefaultPropsOnES6 = + !instance.getDefaultProps || + instance.getDefaultProps.isReactClassApproved; + !noGetDefaultPropsOnES6 + ? warningWithoutStack$1( + false, + "getDefaultProps was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Use a static property to define defaultProps instead.", + name + ) + : void 0; + var noInstancePropTypes = !instance.propTypes; + !noInstancePropTypes + ? warningWithoutStack$1( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; + var noInstanceContextType = !instance.contextType; + !noInstanceContextType + ? warningWithoutStack$1( + false, + "contextType was defined as an instance property on %s. Use a static " + + "property to define contextType instead.", + name + ) + : void 0; + var noInstanceContextTypes = !instance.contextTypes; + !noInstanceContextTypes + ? warningWithoutStack$1( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; + + if ( + ctor.contextType && + ctor.contextTypes && + !didWarnAboutContextTypeAndContextTypes.has(ctor) + ) { + didWarnAboutContextTypeAndContextTypes.add(ctor); + warningWithoutStack$1( + false, + "%s declares both contextTypes and contextType static properties. " + + "The legacy contextTypes property will be ignored.", + name + ); + } + + var noComponentShouldUpdate = + typeof instance.componentShouldUpdate !== "function"; + !noComponentShouldUpdate + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + + "The name is phrased as a question because the function is " + + "expected to return a value.", + name + ) + : void 0; + if ( + ctor.prototype && + ctor.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" + ) { + warningWithoutStack$1( + false, + "%s has a method called shouldComponentUpdate(). " + + "shouldComponentUpdate should not be used when extending React.PureComponent. " + + "Please extend React.Component if shouldComponentUpdate is used.", + getComponentName(ctor) || "A pure component" + ); + } + var noComponentDidUnmount = + typeof instance.componentDidUnmount !== "function"; + !noComponentDidUnmount + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidUnmount(). But there is no such lifecycle method. " + + "Did you mean componentWillUnmount()?", + name + ) + : void 0; + var noComponentDidReceiveProps = + typeof instance.componentDidReceiveProps !== "function"; + !noComponentDidReceiveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidReceiveProps(). But there is no such lifecycle method. " + + "If you meant to update the state in response to changing props, " + + "use componentWillReceiveProps(). If you meant to fetch data or " + + "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", + name + ) + : void 0; + var noComponentWillRecieveProps = + typeof instance.componentWillRecieveProps !== "function"; + !noComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; + var noUnsafeComponentWillRecieveProps = + typeof instance.UNSAFE_componentWillRecieveProps !== "function"; + !noUnsafeComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; + var hasMutatedProps = instance.props !== newProps; + !(instance.props === undefined || !hasMutatedProps) + ? warningWithoutStack$1( + false, + "%s(...): When calling super() in `%s`, make sure to pass " + + "up the same props that your component's constructor was passed.", + name, + name + ) + : void 0; + var noInstanceDefaultProps = !instance.defaultProps; + !noInstanceDefaultProps + ? warningWithoutStack$1( + false, + "Setting defaultProps as an instance property on %s is not supported and will be ignored." + + " Instead, define defaultProps as a static property on %s.", + name, + name + ) + : void 0; + + if ( + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(ctor) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromProps() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noInstanceGetDerivedStateFromCatch = + typeof instance.getDerivedStateFromError !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromError() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof ctor.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() is defined as a static method " + + "and will be ignored. Instead, declare it as an instance method.", + name + ) + : void 0; + var _state = instance.state; + if (_state && (typeof _state !== "object" || isArray$1(_state))) { + warningWithoutStack$1( + false, + "%s.state: must be set to an object or null", + name + ); + } + if (typeof instance.getChildContext === "function") { + !(typeof ctor.childContextTypes === "object") + ? warningWithoutStack$1( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } + } +} + +function adoptClassInstance(workInProgress, instance) { + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; + // The instance needs access to the fiber so that it can schedule updates + set(instance, workInProgress); + { + instance._reactInternalInstance = fakeInternalInstance; + } +} + +function constructClassInstance( + workInProgress, + ctor, + props, + renderExpirationTime +) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = null; + var contextType = ctor.contextType; + + { + if ("contextType" in ctor) { + var isValid = + // Allow null for conditional declaration + contextType === null || + (contextType !== undefined && + contextType.$$typeof === REACT_CONTEXT_TYPE && + contextType._context === undefined); // Not a + + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + + var addendum = ""; + if (contextType === undefined) { + addendum = + " However, it is set to undefined. " + + "This can be caused by a typo or by mixing up named and default imports. " + + "This can also happen due to a circular dependency, so " + + "try moving the createContext() call to a separate file."; + } else if (typeof contextType !== "object") { + addendum = " However, it is set to a " + typeof contextType + "."; + } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { + addendum = " Did you accidentally pass the Context.Provider instead?"; + } else if (contextType._context !== undefined) { + // + addendum = " Did you accidentally pass the Context.Consumer instead?"; + } else { + addendum = + " However, it is set to an object with keys {" + + Object.keys(contextType).join(", ") + + "}."; + } + warningWithoutStack$1( + false, + "%s defines an invalid contextType. " + + "contextType should point to the Context object returned by React.createContext().%s", + getComponentName(ctor) || "Component", + addendum + ); + } + } + } + + if (typeof contextType === "object" && contextType !== null) { + context = readContext(contextType); + } else { + unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + var contextTypes = ctor.contextTypes; + isLegacyContextConsumer = + contextTypes !== null && contextTypes !== undefined; + context = isLegacyContextConsumer + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject; + } + + // Instantiate twice to help detect side-effects. + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + new ctor(props, context); // eslint-disable-line no-new + } + } + + var instance = new ctor(props, context); + var state = (workInProgress.memoizedState = + instance.state !== null && instance.state !== undefined + ? instance.state + : null); + adoptClassInstance(workInProgress, instance); + + { + if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); + warningWithoutStack$1( + false, + "`%s` uses `getDerivedStateFromProps` but its initial state is " + + "%s. This is not recommended. Instead, define the initial state by " + + "assigning an object to `this.state` in the constructor of `%s`. " + + "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", + componentName, + instance.state === null ? "null" : "undefined", + componentName + ); + } + } + + // If new component APIs are defined, "unsafe" lifecycles won't be called. + // Warn about these lifecycles if they are present. + // Don't warn about react-lifecycles-compat polyfilled methods though. + if ( + typeof ctor.getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function" + ) { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + foundWillMountName = "componentWillMount"; + } else if (typeof instance.UNSAFE_componentWillMount === "function") { + foundWillMountName = "UNSAFE_componentWillMount"; + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + foundWillReceivePropsName = "componentWillReceiveProps"; + } else if ( + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + foundWillUpdateName = "componentWillUpdate"; + } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { + foundWillUpdateName = "UNSAFE_componentWillUpdate"; + } + if ( + foundWillMountName !== null || + foundWillReceivePropsName !== null || + foundWillUpdateName !== null + ) { + var _componentName = getComponentName(ctor) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warningWithoutStack$1( + false, + "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + + "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + + "The above lifecycles should be removed. Learn more about this warning here:\n" + + "https://fb.me/react-async-component-lifecycle-hooks", + _componentName, + newApiName, + foundWillMountName !== null ? "\n " + foundWillMountName : "", + foundWillReceivePropsName !== null + ? "\n " + foundWillReceivePropsName + : "", + foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" + ); + } + } + } + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return instance; +} + +function callComponentWillMount(workInProgress, instance) { + startPhaseTimer(workInProgress, "componentWillMount"); + var oldState = instance.state; + + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + + stopPhaseTimer(); + + if (oldState !== instance.state) { + { + warningWithoutStack$1( + false, + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentName(workInProgress.type) || "Component" + ); + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, nextContext); + } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } + stopPhaseTimer(); + + if (instance.state !== oldState) { + { + var componentName = getComponentName(workInProgress.type) || "Component"; + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + warningWithoutStack$1( + false, + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +// Invokes the mount life-cycles on a previously never rendered instance. +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + { + checkClassInstance(workInProgress, ctor, newProps); + } + + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + + var contextType = ctor.contextType; + if (typeof contextType === "object" && contextType !== null) { + instance.context = readContext(contextType); + } else { + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); + } + + { + if (instance.state === newProps) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { + didWarnAboutDirectlyAssigningPropsToState.add(componentName); + warningWithoutStack$1( + false, + "%s: It is not recommended to assign props directly to state " + + "because updates to props won't be reflected in state. " + + "In most cases, it is better to use props directly.", + componentName + ); + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance + ); + + ReactStrictModeWarnings.recordLegacyContextWarning( + workInProgress, + instance + ); + } + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.recordDeprecationWarnings( + workInProgress, + instance + ); + } + } + + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + instance.state = workInProgress.memoizedState; + } + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + typeof ctor.getDerivedStateFromProps !== "function" && + typeof instance.getSnapshotBeforeUpdate !== "function" && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + callComponentWillMount(workInProgress, instance); + // If we had additional state updates during this life-cycle, let's + // process them now. + updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + } + + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } +} + +function resumeMountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextLegacyUnmaskedContext = getUnmaskedContext( + workInProgress, + ctor, + true + ); + nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + startPhaseTimer(workInProgress, "componentWillMount"); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +// Invokes the update life-cycles and returns false if it shouldn't rerender. +function updateClassInstance( + current, + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps); + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillUpdate === "function" || + typeof instance.componentWillUpdate === "function") + ) { + startPhaseTimer(workInProgress, "componentWillUpdate"); + if (typeof instance.componentWillUpdate === "function") { + instance.componentWillUpdate(newProps, newState, nextContext); + } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidUpdate === "function") { + workInProgress.effectTag |= Update; + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + workInProgress.effectTag |= Snapshot; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized props/state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +var didWarnAboutMaps = void 0; +var didWarnAboutGenerators = void 0; +var didWarnAboutStringRefInStrictMode = void 0; +var ownerHasKeyUseWarning = void 0; +var ownerHasFunctionTypeWarning = void 0; +var warnForMissingKey = function(child) {}; + +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefInStrictMode = {}; + + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + + warnForMissingKey = function(child) { + if (child === null || typeof child !== "object") { + return; + } + if (!child._store || child._store.validated || child.key != null) { + return; + } + (function() { + if (!(typeof child._store === "object")) { + throw ReactError( + "React Component in warnForMissingKey should have a _store. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + child._store.validated = true; + + var currentComponentErrorInfo = + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + + getCurrentFiberStackInDev(); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + ); + }; +} + +var isArray = Array.isArray; + +function coerceRef(returnFiber, current$$1, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if (returnFiber.mode & StrictMode) { + var componentName = getComponentName(returnFiber.type) || "Component"; + if (!didWarnAboutStringRefInStrictMode[componentName]) { + warningWithoutStack$1( + false, + 'A string ref, "%s", has been found within a strict mode tree. ' + + "String refs are a source of potential bugs and should be avoided. " + + "We recommend using createRef() instead." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-string-ref", + mixedRef, + getStackByFiberInDevAndProd(returnFiber) + ); + didWarnAboutStringRefInStrictMode[componentName] = true; + } + } + } + + if (element._owner) { + var owner = element._owner; + var inst = void 0; + if (owner) { + var ownerFiber = owner; + (function() { + if (!(ownerFiber.tag === ClassComponent)) { + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + } + })(); + inst = ownerFiber.stateNode; + } + (function() { + if (!inst) { + throw ReactError( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var stringRef = "" + mixedRef; + // Check if previous string ref matches new string ref + if ( + current$$1 !== null && + current$$1.ref !== null && + typeof current$$1.ref === "function" && + current$$1.ref._stringRef === stringRef + ) { + return current$$1.ref; + } + var ref = function(value) { + var refs = inst.refs; + if (refs === emptyRefsObject) { + // This is a lazy pooled frozen object, so we need to initialize. + refs = inst.refs = {}; + } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + ref._stringRef = stringRef; + return ref; + } else { + (function() { + if (!(typeof mixedRef === "string")) { + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } + })(); + (function() { + if (!element._owner) { + throw ReactError( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + })(); + } + } + return mixedRef; +} + +function throwOnInvalidObjectType(returnFiber, newChild) { + if (returnFiber.type !== "textarea") { + var addendum = ""; + { + addendum = + " If you meant to render a collection of children, use an array " + + "instead." + + getCurrentFiberStackInDev(); + } + (function() { + { + throw ReactError( + "Objects are not valid as a React child (found: " + + (Object.prototype.toString.call(newChild) === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + + addendum + ); + } + })(); + } +} + +function warnOnFunctionType() { + var currentComponentErrorInfo = + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + + getCurrentFiberStackInDev(); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); +} + +// This wrapper function exists because I expect to clone the code in each path +// to be able to optimize each path individually by branching early. This needs +// a compiler or we can do it manually. Helpers that don't need this branching +// live outside of this function. +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } + // Deletions are added in reversed order so we add it to the front. + // At this point, the return fiber's effect list is empty except for + // deletions, so we can just append the deletion to the list. The remaining + // effects aren't added until the complete phase. Once we implement + // resuming, this may not be true. + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } + childToDelete.nextEffect = null; + childToDelete.effectTag = Deletion; + } + + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } + + // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. + var childToDelete = currentFirstChild; + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } + return null; + } + + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + var existingChildren = new Map(); + + var existingChild = currentFirstChild; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } + existingChild = existingChild.sibling; + } + return existingChildren; + } + + function useFiber(fiber, pendingProps, expirationTime) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps, expirationTime); + clone.index = 0; + clone.sibling = null; + return clone; + } + + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) { + // Noop. + return lastPlacedIndex; + } + var current$$1 = newFiber.alternate; + if (current$$1 !== null) { + var oldIndex = current$$1.index; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } + } + + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.effectTag = Placement; + } + return newFiber; + } + + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (current$$1 === null || current$$1.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (current$$1 !== null && current$$1.elementType === element.type) { + // Move based on index + var existing = useFiber(current$$1, element.props, expirationTime); + existing.ref = coerceRef(returnFiber, current$$1, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + // Insert + var created = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + created.ref = coerceRef(returnFiber, current$$1, element); + created.return = returnFiber; + return created; + } + } + + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + current$$1 === null || + current$$1.tag !== HostPortal || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber( + current$$1, + portal.children || [], + expirationTime + ); + existing.return = returnFiber; + return existing; + } + } + + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (current$$1 === null || current$$1.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, fragment, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function createChild(returnFiber, newChild, expirationTime) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + expirationTime + ); + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; + } + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + _created2.return = returnFiber; + return _created2; + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + ); + _created3.return = returnFiber; + return _created3; + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + // Update the fiber if the keys match, otherwise return null. + + var key = oldFiber !== null ? oldFiber.key : null; + + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { + return null; + } + return updateTextNode( + returnFiber, + oldFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ); + } + return updateElement( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } + + return updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode( + returnFiber, + matchedFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + _matchedFiber, + newChild.props.children, + expirationTime, + newChild.key + ); + } + return updateElement( + returnFiber, + _matchedFiber, + newChild, + expirationTime + ); + } + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + return updatePortal( + returnFiber, + _matchedFiber2, + newChild, + expirationTime + ); + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + /** + * Warns if there is a duplicate or missing key + */ + function warnOnInvalidKey(child, knownKeys) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child); + var key = child.key; + if (typeof key !== "string") { + break; + } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } + warning$1( + false, + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key + ); + break; + default: + break; + } + } + return knownKeys; + } + + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. + + { + // First, validate keys. + var knownKeys = null; + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + ); + if (_newFiber === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } + previousNewFiber = _newFiber; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + ); + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } + previousNewFiber = _newFiber2; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + + var iteratorFn = getIteratorFn(newChildrenIterable); + (function() { + if (!(typeof iteratorFn === "function")) { + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && + // $FlowFixMe Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + !didWarnAboutGenerators + ? warning$1( + false, + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ) + : void 0; + didWarnAboutGenerators = true; + } + + // Warn about using Maps as children + if (newChildrenIterable.entries === iteratorFn) { + !didWarnAboutMaps + ? warning$1( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead." + ) + : void 0; + didWarnAboutMaps = true; + } + + // First, validate keys. + // We'll get a different iterator later for the main pass. + var _newChildren = iteratorFn.call(newChildrenIterable); + if (_newChildren) { + var knownKeys = null; + var _step = _newChildren.next(); + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + } + + var newChildren = iteratorFn.call(newChildrenIterable); + (function() { + if (!(newChildren != null)) { + throw ReactError("An iterable object provided no iterator."); + } + })(); + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + + var step = newChildren.next(); + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, expirationTime); + if (_newFiber3 === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } + previousNewFiber = _newFiber3; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + expirationTime + ); + if (_newFiber4 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber4.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber4.key === null ? newIdx : _newFiber4.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } + previousNewFiber = _newFiber4; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + expirationTime + ) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + // The existing first child is not a text node so we need to create one + // and delete the existing ones. + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + expirationTime + ) { + var key = element.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === Fragment + ? element.type === REACT_FRAGMENT_TYPE + : child.elementType === element.type + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber( + child, + element.type === REACT_FRAGMENT_TYPE + ? element.props.children + : element.props, + expirationTime + ); + existing.ref = coerceRef(returnFiber, child, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + expirationTime, + element.key + ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } + + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + expirationTime + ) { + var key = portal.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === HostPortal && + child.stateNode.containerInfo === portal.containerInfo && + child.stateNode.implementation === portal.implementation + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || [], expirationTime); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } + + // Handle object types + var isObject = typeof newChild === "object" && newChild !== null; + + if (isObject) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + } + } + + if (typeof newChild === "string" || typeof newChild === "number") { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + expirationTime + ) + ); + } + + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (isObject) { + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + if (typeof newChild === "undefined" && !isUnkeyedTopLevelFragment) { + // If the new child is undefined, and the return fiber is a composite + // component, throw an error. If Fiber return types are disabled, + // we already threw above. + switch (returnFiber.tag) { + case ClassComponent: { + { + var instance = returnFiber.stateNode; + if (instance.render._isMockFunction) { + // We allow auto-mocks to proceed as if they're returning null. + break; + } + } + } + // Intentionally fall through to the next case, which handles both + // functions and classes + // eslint-disable-next-lined no-fallthrough + case FunctionComponent: { + var Component = returnFiber.type; + (function() { + { + throw ReactError( + (Component.displayName || Component.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + ); + } + })(); + } + } + } + + // Remaining cases are all treated as empty. + return deleteRemainingChildren(returnFiber, currentFirstChild); + } + + return reconcileChildFibers; +} + +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); + +function cloneChildFibers(current$$1, workInProgress) { + (function() { + if (!(current$$1 === null || workInProgress.child === current$$1.child)) { + throw ReactError("Resuming work not yet implemented."); + } + })(); + + if (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + workInProgress.child = newChild; + + newChild.return = workInProgress; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + newChild.return = workInProgress; + } + newChild.sibling = null; +} + +var NO_CONTEXT = {}; + +var contextStackCursor$1 = createCursor(NO_CONTEXT); +var contextFiberStackCursor = createCursor(NO_CONTEXT); +var rootInstanceStackCursor = createCursor(NO_CONTEXT); + +function requiredContext(c) { + (function() { + if (!(c !== NO_CONTEXT)) { + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + return c; +} + +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} + +function pushHostContainer(fiber, nextRootInstance) { + // Push current root instance onto the stack; + // This allows us to reset root when portals are popped. + push(rootInstanceStackCursor, nextRootInstance, fiber); + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + + // Finally, we need to push the host context to the stack. + // However, we can't just call getRootHostContext() and push it because + // we'd have a different number of entries on the stack depending on + // whether getRootHostContext() throws somewhere in renderer code or not. + // So we push an empty value first. This lets us safely unwind on errors. + push(contextStackCursor$1, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, nextRootContext, fiber); +} + +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} + +function getHostContext() { + var context = requiredContext(contextStackCursor$1.current); + return context; +} + +function pushHostContext(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContext(context, fiber.type, rootInstance); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventComponent(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContextForEventComponent(context); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventTarget(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var eventTargetType = fiber.type.type; + var nextContext = getChildHostContextForEventTarget(context, eventTargetType); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function popHostContext(fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + if (contextFiberStackCursor.current !== fiber) { + return; + } + + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); +} + +var NoEffect$1 = /* */ 0; +var UnmountSnapshot = /* */ 2; +var UnmountMutation = /* */ 4; +var MountMutation = /* */ 8; +var UnmountLayout = /* */ 16; +var MountLayout = /* */ 32; +var MountPassive = /* */ 64; +var UnmountPassive = /* */ 128; + +var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; + +var didWarnAboutMismatchedHooksForComponent = void 0; +{ + didWarnAboutMismatchedHooksForComponent = new Set(); +} + +// These are set right before calling the component. +var renderExpirationTime$1 = NoWork; +// The work-in-progress fiber. I've named it differently to distinguish it from +// the work-in-progress hook. +var currentlyRenderingFiber$1 = null; + +// Hooks are stored as a linked list on the fiber's memoizedState field. The +// current hook list is the list that belongs to the current fiber. The +// work-in-progress hook list is a new list that will be added to the +// work-in-progress fiber. +var currentHook = null; +var nextCurrentHook = null; +var firstWorkInProgressHook = null; +var workInProgressHook = null; +var nextWorkInProgressHook = null; + +var remainingExpirationTime = NoWork; +var componentUpdateQueue = null; +var sideEffectTag = 0; + +// Updates scheduled during render will trigger an immediate re-render at the +// end of the current pass. We can't store these updates on the normal queue, +// because if the work is aborted, they should be discarded. Because this is +// a relatively rare case, we also don't want to add an additional field to +// either the hook or queue object types. So we store them in a lazily create +// map of queue -> render-phase updates, which are discarded once the component +// completes without re-rendering. + +// Whether an update was scheduled during the currently executing render pass. +var didScheduleRenderPhaseUpdate = false; +// Lazily created map of render-phase updates +var renderPhaseUpdates = null; +// Counter to prevent infinite loops. +var numberOfReRenders = 0; +var RE_RENDER_LIMIT = 25; + +// In DEV, this is the name of the currently executing primitive hook +var currentHookNameInDev = null; + +// In DEV, this list ensures that hooks are called in the same order between renders. +// The list stores the order of hooks used during the initial render (mount). +// Subsequent renders (updates) reference this list. +var hookTypesDev = null; +var hookTypesUpdateIndexDev = -1; + +function mountHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev === null) { + hookTypesDev = [hookName]; + } else { + hookTypesDev.push(hookName); + } + } +} + +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } + } + } +} + +function checkDepsAreArrayDev(deps) { + { + if (deps !== undefined && deps !== null && !Array.isArray(deps)) { + // Verify deps, but only on mount to avoid extra checks. + // It's unlikely their type would change as usually you define them inline. + warning$1( + false, + "%s received a final argument that is not an array (instead, received `%s`). When " + + "specified, the final argument must be an array.", + currentHookNameInDev, + typeof deps + ); + } + } +} + +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentName(currentlyRenderingFiber$1.type); + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); + + if (hookTypesDev !== null) { + var table = ""; + + var secondColumnStart = 30; + + for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { + var oldHookName = hookTypesDev[i]; + var newHookName = + i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; + + var row = i + 1 + ". " + oldHookName; + + // Extra space so second column lines up + // lol @ IE not supporting String#repeat + while (row.length < secondColumnStart) { + row += " "; + } + + row += newHookName + "\n"; + + table += row; + } + + warning$1( + false, + "React has detected a change in the order of Hooks called by %s. " + + "This will lead to bugs and errors if not fixed. " + + "For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n" + + " Previous render Next render\n" + + " ------------------------------------------------------\n" + + "%s" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + componentName, + table + ); + } + } + } +} + +function throwInvalidHookError() { + (function() { + { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); + } + })(); +} + +function areHookInputsEqual(nextDeps, prevDeps) { + if (prevDeps === null) { + { + warning$1( + false, + "%s received a final argument during this render, but not during " + + "the previous render. Even though the final argument is optional, " + + "its type cannot change between renders.", + currentHookNameInDev + ); + } + return false; + } + + { + // Don't bother comparing lengths in prod because these arrays should be + // passed inline. + if (nextDeps.length !== prevDeps.length) { + warning$1( + false, + "The final argument passed to %s changed size between renders. The " + + "order and size of this array must remain constant.\n\n" + + "Previous: %s\n" + + "Incoming: %s", + currentHookNameInDev, + "[" + prevDeps.join(", ") + "]", + "[" + nextDeps.join(", ") + "]" + ); + } + } + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { + if (is(nextDeps[i], prevDeps[i])) { + continue; + } + return false; + } + return true; +} + +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = current !== null ? current.memoizedState : null; + + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; + } + + // The following should have already been reset + // currentHook = null; + // workInProgressHook = null; + + // remainingExpirationTime = NoWork; + // componentUpdateQueue = null; + + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + // sideEffectTag = 0; + + // TODO Warn if no hooks are used at all during mount, then some are used during update. + // Currently we will identify the update render as a mount because nextCurrentHook === null. + // This is tricky because it's valid for certain types of components (e.g. React.lazy) + + // Using nextCurrentHook to differentiate between mount/update only works if at least one stateful hook is used. + // Non-stateful hooks (e.g. context) don't get added to memoizedState, + // so nextCurrentHook would be null during updates and mounts. + { + if (nextCurrentHook !== null) { + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + } else if (hookTypesDev !== null) { + // This dispatcher handles an edge case where a component is updating, + // but no stateful hooks have been used. + // We want to match the production code behavior (which will use HooksDispatcherOnMount), + // but with the extra DEV validation to ensure hooks ordering hasn't changed. + // This dispatcher does that. + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + } + } + + var children = Component(props, refOrContext); + + if (didScheduleRenderPhaseUpdate) { + do { + didScheduleRenderPhaseUpdate = false; + numberOfReRenders += 1; + + // Start over from the beginning of the list + nextCurrentHook = current !== null ? current.memoizedState : null; + nextWorkInProgressHook = firstWorkInProgressHook; + + currentHook = null; + workInProgressHook = null; + componentUpdateQueue = null; + + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; + } + + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + + children = Component(props, refOrContext); + } while (didScheduleRenderPhaseUpdate); + + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + var renderedWork = currentlyRenderingFiber$1; + + renderedWork.memoizedState = firstWorkInProgressHook; + renderedWork.expirationTime = remainingExpirationTime; + renderedWork.updateQueue = componentUpdateQueue; + renderedWork.effectTag |= sideEffectTag; + + { + renderedWork._debugHookTypes = hookTypesDev; + } + + // This check uses currentHook so that it works the same in DEV and prod bundles. + // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + currentHookNameInDev = null; + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + // These were reset above + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + + (function() { + if (!!didRenderTooFewHooks) { + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + } + })(); + + return children; +} + +function bailoutHooks(current, workInProgress, expirationTime) { + workInProgress.updateQueue = current.updateQueue; + workInProgress.effectTag &= ~(Passive | Update); + if (current.expirationTime <= expirationTime) { + current.expirationTime = NoWork; + } +} + +function resetHooks() { + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + // This is used to reset the state of this module when a component throws. + // It's also called inside mountIndeterminateComponent if we determine the + // component is a module-style component. + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + + currentHookNameInDev = null; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + didScheduleRenderPhaseUpdate = false; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} + +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + + baseState: null, + queue: null, + baseUpdate: null, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list + firstWorkInProgressHook = workInProgressHook = hook; + } else { + // Append to the end of the list + workInProgressHook = workInProgressHook.next = hook; + } + return workInProgressHook; +} + +function updateWorkInProgressHook() { + // This function is used both for updates and for re-renders triggered by a + // render phase update. It assumes there is either a current hook we can + // clone, or a work-in-progress hook from a previous render pass that we can + // use as a base. When we reach the end of the base list, we must switch to + // the dispatcher used for mounts. + if (nextWorkInProgressHook !== null) { + // There's already a work-in-progress. Reuse it. + workInProgressHook = nextWorkInProgressHook; + nextWorkInProgressHook = workInProgressHook.next; + + currentHook = nextCurrentHook; + nextCurrentHook = currentHook !== null ? currentHook.next : null; + } else { + // Clone from the current hook. + (function() { + if (!(nextCurrentHook !== null)) { + throw ReactError( + "Rendered more hooks than during the previous render." + ); + } + })(); + currentHook = nextCurrentHook; + + var newHook = { + memoizedState: currentHook.memoizedState, + + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list. + workInProgressHook = firstWorkInProgressHook = newHook; + } else { + // Append to the end of the list. + workInProgressHook = workInProgressHook.next = newHook; + } + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} + +function createFunctionComponentUpdateQueue() { + return { + lastEffect: null + }; +} + +function basicStateReducer(state, action) { + return typeof action === "function" ? action(state) : action; +} + +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState = void 0; + if (init !== undefined) { + initialState = init(initialArg); + } else { + initialState = initialArg; + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; + (function() { + if (!(queue !== null)) { + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + } + })(); + + queue.lastRenderedReducer = reducer; + + if (numberOfReRenders > 0) { + // This is a re-render. Apply the new render phase updates to the previous + var _dispatch = queue.dispatch; + if (renderPhaseUpdates !== null) { + // Render phase updates are stored in a map of queue -> linked list + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate !== undefined) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + var update = firstRenderPhaseUpdate; + do { + // Process this render phase update. We don't have to check the + // priority because it will always be the same as the current + // render's. + var _action = update.action; + newState = reducer(newState, _action); + update = update.next; + } while (update !== null); + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = newState; + // Don't persist the state accumlated from the render phase updates to + // the base state unless the queue is empty. + // TODO: Not sure if this is the desired semantics, but it's what we + // do for gDSFP. I can't remember why. + if (hook.baseUpdate === queue.last) { + hook.baseState = newState; + } + + queue.lastRenderedState = newState; + + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + + // The last update in the entire queue + var last = queue.last; + // The last update that is part of the base state. + var baseUpdate = hook.baseUpdate; + var baseState = hook.baseState; + + // Find the first unprocessed update. + var first = void 0; + if (baseUpdate !== null) { + if (last !== null) { + // For the first update, the queue is a circular linked list where + // `queue.last.next = queue.first`. Once the first update commits, and + // the `baseUpdate` is no longer empty, we can unravel the list. + last.next = null; + } + first = baseUpdate.next; + } else { + first = last !== null ? last.next : null; + } + if (first !== null) { + var _newState = baseState; + var newBaseState = null; + var newBaseUpdate = null; + var prevUpdate = baseUpdate; + var _update = first; + var didSkip = false; + do { + var updateExpirationTime = _update.expirationTime; + if (updateExpirationTime < renderExpirationTime$1) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + if (!didSkip) { + didSkip = true; + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + // Update the remaining priority in the queue. + if (updateExpirationTime > remainingExpirationTime) { + remainingExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process this update. + if (_update.eagerReducer === reducer) { + // If this update was processed eagerly, and its reducer matches the + // current reducer, we can use the eagerly computed state. + _newState = _update.eagerState; + } else { + var _action2 = _update.action; + _newState = reducer(_newState, _action2); + } + } + prevUpdate = _update; + _update = _update.next; + } while (_update !== null && _update !== first); + + if (!didSkip) { + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(_newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = _newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = newBaseState; + + queue.lastRenderedState = _newState; + } + + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} + +function mountState(initialState) { + var hook = mountWorkInProgressHook(); + if (typeof initialState === "function") { + initialState = initialState(); + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateState(initialState) { + return updateReducer(basicStateReducer, initialState); +} + +function pushEffect(tag, create, destroy, deps) { + var effect = { + tag: tag, + create: create, + destroy: destroy, + deps: deps, + // Circular + next: null + }; + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var _lastEffect = componentUpdateQueue.lastEffect; + if (_lastEffect === null) { + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var firstEffect = _lastEffect.next; + _lastEffect.next = effect; + effect.next = firstEffect; + componentUpdateQueue.lastEffect = effect; + } + } + return effect; +} + +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { current: initialValue }; + { + Object.seal(ref); + } + hook.memoizedState = ref; + return ref; +} + +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} + +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); +} + +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var destroy = undefined; + + if (currentHook !== null) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (nextDeps !== null) { + var prevDeps = prevEffect.deps; + if (areHookInputsEqual(nextDeps, prevDeps)) { + pushEffect(NoEffect$1, create, destroy, nextDeps); + return; + } + } + } + + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); +} + +function mountEffect(create, deps) { + return mountEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function updateEffect(create, deps) { + return updateEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function mountLayoutEffect(create, deps) { + return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function imperativeHandleEffect(create, ref) { + if (typeof ref === "function") { + var refCallback = ref; + var _inst = create(); + refCallback(_inst); + return function() { + refCallback(null); + }; + } else if (ref !== null && ref !== undefined) { + var refObject = ref; + { + !refObject.hasOwnProperty("current") + ? warning$1( + false, + "Expected useImperativeHandle() first argument to either be a " + + "ref callback or React.createRef() object. Instead received: %s.", + "an object with keys {" + Object.keys(refObject).join(", ") + "}" + ) + : void 0; + } + var _inst2 = create(); + refObject.current = _inst2; + return function() { + refObject.current = null; + }; + } +} + +function mountImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return mountEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function updateImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return updateEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function mountDebugValue(value, formatterFn) { + // This hook is normally a no-op. + // The react-debug-hooks package injects its own implementation + // so that e.g. DevTools can display custom hook values. +} + +var updateDebugValue = mountDebugValue; + +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function updateMemo(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + // Assume these are defined. If they're not, areHookInputsEqual will warn. + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function dispatchAction(fiber, queue, action) { + (function() { + if (!(numberOfReRenders < RE_RENDER_LIMIT)) { + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + } + })(); + + { + !(arguments.length <= 3) + ? warning$1( + false, + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." + ) + : void 0; + } + + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (alternate !== null && alternate === currentlyRenderingFiber$1) + ) { + // This is a render phase update. Stash it in a lazily-created map of + // queue -> linked list of updates. After this render pass, we'll restart + // and apply the stashed updates on top of the work-in-progress hook. + didScheduleRenderPhaseUpdate = true; + var update = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + if (renderPhaseUpdates === null) { + renderPhaseUpdates = new Map(); + } + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate === undefined) { + renderPhaseUpdates.set(queue, update); + } else { + // Append the update to the end of the list. + var lastRenderPhaseUpdate = firstRenderPhaseUpdate; + while (lastRenderPhaseUpdate.next !== null) { + lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; + } + lastRenderPhaseUpdate.next = update; + } + } else { + flushPassiveEffects(); + + var currentTime = requestCurrentTime(); + var _expirationTime = computeExpirationForFiber(currentTime, fiber); + + var _update2 = { + expirationTime: _expirationTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + + // Append the update to the end of the list. + var _last = queue.last; + if (_last === null) { + // This is the first update. Create a circular list. + _update2.next = _update2; + } else { + var first = _last.next; + if (first !== null) { + // Still circular. + _update2.next = first; + } + _last.next = _update2; + } + queue.last = _update2; + + if ( + fiber.expirationTime === NoWork && + (alternate === null || alternate.expirationTime === NoWork) + ) { + // The queue is currently empty, which means we can eagerly compute the + // next state before entering the render phase. If the new state is the + // same as the current state, we may be able to bail out entirely. + var _lastRenderedReducer = queue.lastRenderedReducer; + if (_lastRenderedReducer !== null) { + var prevDispatcher = void 0; + { + prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + } + try { + var currentState = queue.lastRenderedState; + var _eagerState = _lastRenderedReducer(currentState, action); + // Stash the eagerly computed state, and the reducer used to compute + // it, on the update object. If the reducer hasn't changed by the + // time we enter the render phase, then the eager state can be used + // without calling the reducer again. + _update2.eagerReducer = _lastRenderedReducer; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) { + // Fast path. We can bail out without scheduling React to re-render. + // It's still possible that we'll need to rebase this update later, + // if the component re-renders for a different reason and by that + // time the reducer has changed. + return; + } + } catch (error) { + // Suppress the error. It will throw again in the render phase. + } finally { + { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + } + } + } + { + // jest isn't a 'global', it's just exposed to tests via a wrapped function + // further, this isn't a test file, so flow doesn't recognize the symbol. So... + // $FlowExpectedError - because requirements don't give a damn about your type sigs. + if ("undefined" !== typeof jest) { + warnIfNotCurrentlyActingUpdatesInDev(fiber); + } + } + scheduleWork(fiber, _expirationTime); + } +} + +var ContextOnlyDispatcher = { + readContext: readContext, + + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError +}; + +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; + +{ + var warnInvalidContextAccess = function() { + warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + }; + + var warnInvalidHookAccess = function() { + warning$1( + false, + "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + + "You can only call Hooks at the top level of your React function. " + + "For more information, see " + + "https://fb.me/rules-of-hooks" + ); + }; + + HooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; +} + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var now$1 = Scheduler.unstable_now; + +var commitTime = 0; +var profilerStartTime = -1; + +function getCommitTime() { + return commitTime; +} + +function recordCommitTime() { + if (!enableProfilerTimer) { + return; + } + commitTime = now$1(); +} + +function startProfilerTimer(fiber) { + if (!enableProfilerTimer) { + return; + } + + profilerStartTime = now$1(); + + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now$1(); + } +} + +function stopProfilerTimerIfRunning(fiber) { + if (!enableProfilerTimer) { + return; + } + profilerStartTime = -1; +} + +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (!enableProfilerTimer) { + return; + } + + if (profilerStartTime >= 0) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; + } + profilerStartTime = -1; + } +} + +// The deepest Fiber on the stack involved in a hydration context. +// This may have been an insertion or a hydration. +var hydrationParentFiber = null; +var nextHydratableInstance = null; +var isHydrating = false; + +function enterHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = getFirstHydratableChild(parentInstance); + hydrationParentFiber = fiber; + isHydrating = true; + return true; +} + +function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + return false; + } + + var suspenseInstance = fiber.stateNode; + nextHydratableInstance = getNextHydratableSibling(suspenseInstance); + popToNextHostParent(fiber); + isHydrating = true; + return true; +} + +function deleteHydratableInstance(returnFiber, instance) { + { + switch (returnFiber.tag) { + case HostRoot: + didNotHydrateContainerInstance( + returnFiber.stateNode.containerInfo, + instance + ); + break; + case HostComponent: + didNotHydrateInstance( + returnFiber.type, + returnFiber.memoizedProps, + returnFiber.stateNode, + instance + ); + break; + } + } + + var childToDelete = createFiberFromHostInstanceForDeletion(); + childToDelete.stateNode = instance; + childToDelete.return = returnFiber; + childToDelete.effectTag = Deletion; + + // This might seem like it belongs on progressedFirstDeletion. However, + // these children are not part of the reconciliation list of children. + // Even if we abort and rereconcile the children, that will try to hydrate + // again and the nodes are still in the host tree so these will be + // recreated. + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } +} + +function insertNonHydratedInstance(returnFiber, fiber) { + fiber.effectTag |= Placement; + { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + switch (fiber.tag) { + case HostComponent: + var type = fiber.type; + var props = fiber.pendingProps; + didNotFindHydratableContainerInstance(parentContainer, type, props); + break; + case HostText: + var text = fiber.pendingProps; + didNotFindHydratableContainerTextInstance(parentContainer, text); + break; + case SuspenseComponent: + didNotFindHydratableContainerSuspenseInstance(parentContainer); + break; + } + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + switch (fiber.tag) { + case HostComponent: + var _type = fiber.type; + var _props = fiber.pendingProps; + didNotFindHydratableInstance( + parentType, + parentProps, + parentInstance, + _type, + _props + ); + break; + case HostText: + var _text = fiber.pendingProps; + didNotFindHydratableTextInstance( + parentType, + parentProps, + parentInstance, + _text + ); + break; + case SuspenseComponent: + didNotFindHydratableSuspenseInstance( + parentType, + parentProps, + parentInstance + ); + break; + } + break; + } + default: + return; + } + } +} + +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case HostComponent: { + var type = fiber.type; + var props = fiber.pendingProps; + var instance = canHydrateInstance(nextInstance, type, props); + if (instance !== null) { + fiber.stateNode = instance; + return true; + } + return false; + } + case HostText: { + var text = fiber.pendingProps; + var textInstance = canHydrateTextInstance(nextInstance, text); + if (textInstance !== null) { + fiber.stateNode = textInstance; + return true; + } + return false; + } + case SuspenseComponent: { + if (enableSuspenseServerRenderer) { + var suspenseInstance = canHydrateSuspenseInstance(nextInstance); + if (suspenseInstance !== null) { + // Downgrade the tag to a dehydrated component until we've hydrated it. + fiber.tag = DehydratedSuspenseComponent; + fiber.stateNode = suspenseInstance; + return true; + } + } + return false; + } + default: + return false; + } +} + +function tryToClaimNextHydratableInstance(fiber) { + if (!isHydrating) { + return; + } + var nextInstance = nextHydratableInstance; + if (!nextInstance) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber, nextInstance)) { + // If we can't hydrate this instance let's try the next one. + // We use this as a heuristic. It's based on intuition and not data so it + // might be flawed or unnecessary. + nextInstance = getNextHydratableSibling(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + // We matched the next one, we'll now assume that the first one was + // superfluous and we'll delete it. Since we can't eagerly delete it + // we'll have to schedule a deletion. To do that, this node needs a dummy + // fiber associated with it. + deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); +} + +function prepareToHydrateHostInstance( + fiber, + rootContainerInstance, + hostContext +) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var instance = fiber.stateNode; + var updatePayload = hydrateInstance( + instance, + fiber.type, + fiber.memoizedProps, + rootContainerInstance, + hostContext, + fiber + ); + // TODO: Type this specific to this type of component. + fiber.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. + if (updatePayload !== null) { + return true; + } + return false; +} + +function prepareToHydrateHostTextInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var textInstance = fiber.stateNode; + var textContent = fiber.memoizedProps; + var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); + { + if (shouldUpdate) { + // We assume that prepareToHydrateHostTextInstance is called in a context where the + // hydration parent is the parent host component of this host text. + var returnFiber = hydrationParentFiber; + if (returnFiber !== null) { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + didNotMatchHydratedContainerTextInstance( + parentContainer, + textInstance, + textContent + ); + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + didNotMatchHydratedTextInstance( + parentType, + parentProps, + parentInstance, + textInstance, + textContent + ); + break; + } + } + } + } + } + return shouldUpdate; +} + +function skipPastDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected skipPastDehydratedSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + var suspenseInstance = fiber.stateNode; + (function() { + if (!suspenseInstance) { + throw ReactError( + "Expected to have a hydrated suspense instance. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance( + suspenseInstance + ); +} + +function popToNextHostParent(fiber) { + var parent = fiber.return; + while ( + parent !== null && + parent.tag !== HostComponent && + parent.tag !== HostRoot && + parent.tag !== DehydratedSuspenseComponent + ) { + parent = parent.return; + } + hydrationParentFiber = parent; +} + +function popHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + if (fiber !== hydrationParentFiber) { + // We're deeper than the current hydration context, inside an inserted + // tree. + return false; + } + if (!isHydrating) { + // If we're not currently hydrating but we're in a hydration context, then + // we were an insertion and now need to pop up reenter hydration of our + // siblings. + popToNextHostParent(fiber); + isHydrating = true; + return false; + } + + var type = fiber.type; + + // If we have any remaining hydratable nodes, we need to delete them now. + // We only do this deeper than head and body since they tend to have random + // other nodes in them. We also ignore components with pure text content in + // side of them. + // TODO: Better heuristic. + if ( + fiber.tag !== HostComponent || + (type !== "head" && + type !== "body" && + !shouldSetTextContent(type, fiber.memoizedProps)) + ) { + var nextInstance = nextHydratableInstance; + while (nextInstance) { + deleteHydratableInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); + } + } + + popToNextHostParent(fiber); + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; + return true; +} + +function resetHydrationState() { + if (!supportsHydration) { + return; + } + + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; +} + +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; + +var didReceiveUpdate = false; + +var didWarnAboutBadClass = void 0; +var didWarnAboutModulePatternComponent = void 0; +var didWarnAboutContextTypeOnFunctionComponent = void 0; +var didWarnAboutGetDerivedStateOnFunctionComponent = void 0; +var didWarnAboutFunctionRefs = void 0; +var didWarnAboutReassigningProps = void 0; +var didWarnAboutMaxDuration = void 0; + +{ + didWarnAboutBadClass = {}; + didWarnAboutModulePatternComponent = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutMaxDuration = false; +} + +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + if (current$$1 === null) { + // If this is a fresh new component that hasn't been rendered yet, we + // won't update its child set by applying minimal side-effects. Instead, + // we will add them all to the child before it gets rendered. That means + // we can optimize this reconciliation pass by not tracking side-effects. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // If the current child is the same as the work in progress, it means that + // we haven't yet started any work on these children. Therefore, we use + // the clone algorithm to create a copy of all the current children. + + // If we had any progressed work already, that is invalid at this point so + // let's throw it out. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); + } +} + +function forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + // This function is fork of reconcileChildren. It's used in cases where we + // want to reconcile without matching against the existing set. This has the + // effect of all current children being unmounted; even if the type and key + // are the same, the old child is unmounted and a new child is created. + // + // To do this, we're going to go through the reconcile algorithm twice. In + // the first pass, we schedule a deletion for all the current children by + // passing null. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + ); + // In the second pass, we mount the new children. The trick here is that we + // pass null in place of where we usually pass the current child set. This has + // the effect of remounting all children regardless of whether their their + // identity matches. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); +} + +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens after the first render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var render = Component.render; + var ref = workInProgress.ref; + + // The rest is a fork of updateFunctionComponent + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (current$$1 === null) { + var type = Component.type; + if ( + isSimpleFunctionComponent(type) && + Component.compare === null && + // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined + ) { + // If this is a plain function component without default props, + // and with only the default shallow comparison, we upgrade it + // to a SimpleMemoComponent to allow fast path updates. + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = type; + { + validateFunctionComponentInDev(workInProgress, type); + } + return updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ); + } + { + var innerPropTypes = type.propTypes; + if (innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(type), + getCurrentFiberStackInDev + ); + } + } + var child = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } + { + var _type = Component.type; + var _innerPropTypes = _type.propTypes; + if (_innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + _innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(_type), + getCurrentFiberStackInDev + ); + } + } + var currentChild = current$$1.child; // This is always exactly one child + if (updateExpirationTime < renderExpirationTime) { + // This will be the props with resolved defaultProps, + // unlike current.memoizedProps which will be the unresolved ones. + var prevProps = currentChild.memoizedProps; + // Default to shallow comparison + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; + if ( + compare(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + var newChild = createWorkInProgress( + currentChild, + nextProps, + renderExpirationTime + ); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} + +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens when the inner render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var outerMemoType = workInProgress.elementType; + if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { + // We warn when you define propTypes on lazy() + // so let's just skip over it to find memo() outer wrapper. + // Inner props for memo are validated later. + outerMemoType = refineResolvedLazyComponent(outerMemoType); + } + var outerPropTypes = outerMemoType && outerMemoType.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + nextProps, // Resolved (SimpleMemoComponent has no defaultProps) + "prop", + getComponentName(outerMemoType), + getCurrentFiberStackInDev + ); + } + // Inner propTypes will be validated in the function component path. + } + } + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + if ( + shallowEqual(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + didReceiveUpdate = false; + if (updateExpirationTime < renderExpirationTime) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + } + return updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} + +function updateFragment(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMode(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateProfiler(current$$1, workInProgress, renderExpirationTime) { + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (current$$1 === null && ref !== null) || + (current$$1 !== null && current$$1.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.effectTag |= Ref; + } +} + +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + var instance = workInProgress.stateNode; + var shouldUpdate = void 0; + if (instance === null) { + if (current$$1 !== null) { + // An class component without an instance only mounts if it suspended + // inside a non- concurrent tree, in an inconsistent state. We want to + // tree it like a new mount, even though an empty version of it already + // committed. Disconnect the alternate pointers. + current$$1.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + // In the initial pass we might need to construct the instance. + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + shouldUpdate = true; + } else if (current$$1 === null) { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } else { + shouldUpdate = updateClassInstance( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } + var nextUnitOfWork = finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime + ); + { + var inst = workInProgress.stateNode; + if (inst.props !== nextProps) { + !didWarnAboutReassigningProps + ? warning$1( + false, + "It looks like %s is reassigning its own `this.props` while rendering. " + + "This is not supported and can lead to confusing bugs.", + getComponentName(workInProgress.type) || "a component" + ) + : void 0; + didWarnAboutReassigningProps = true; + } + } + return nextUnitOfWork; +} + +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current$$1, workInProgress); + + var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; + + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); + } + + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + var instance = workInProgress.stateNode; + + // Rerender + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = void 0; + if ( + didCaptureError && + typeof Component.getDerivedStateFromError !== "function" + ) { + // If we captured an error, but getDerivedStateFrom catch is not defined, + // unmount all the children. componentDidCatch will schedule an update to + // re-render a fallback. This is temporary until we migrate everyone to + // the new API. + // TODO: Warn in a future release. + nextChildren = null; + + if (enableProfilerTimer) { + stopProfilerTimerIfRunning(workInProgress); + } + } else { + { + setCurrentPhase("render"); + nextChildren = instance.render(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + instance.render(); + } + setCurrentPhase(null); + } + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + if (current$$1 !== null && didCaptureError) { + // If we're recovering from an error, reconcile without reusing any of + // the existing children. Conceptually, the normal children and the children + // that are shown on error are two different sets, so we shouldn't reuse + // normal children even if their identities match. + forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + + // Memoize state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. + workInProgress.memoizedState = instance.state; + + // The context might have changed so we need to recalculate it. + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } + + return workInProgress.child; +} + +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + if (root.pendingContext) { + pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } + pushHostContainer(workInProgress, root.containerInfo); +} + +function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { + pushHostRootContext(workInProgress); + var updateQueue = workInProgress.updateQueue; + (function() { + if (!(updateQueue !== null)) { + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState !== null ? prevState.element : null; + processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + null, + renderExpirationTime + ); + var nextState = workInProgress.memoizedState; + // Caution: React DevTools currently depends on this property + // being called "element". + var nextChildren = nextState.element; + if (nextChildren === prevChildren) { + // If the state is the same as before, that's a bailout because we had + // no work that expires at this time. + resetHydrationState(); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + var root = workInProgress.stateNode; + if ( + (current$$1 === null || current$$1.child === null) && + root.hydrate && + enterHydrationState(workInProgress) + ) { + // If we don't have any current children this might be the first pass. + // We always try to hydrate. If this isn't a hydration pass there won't + // be any children to hydrate which is effectively the same thing as + // not hydrating. + + // This is a bit of a hack. We track the host root as a placement to + // know that we're currently in a mounting state. That way isMounted + // works as expected. We must reset this before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag |= Placement; + + // Ensure that children mount into this root without tracking + // side-effects. This ensures that we don't store Placement effects on + // nodes that will be hydrated. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // Otherwise reset hydration state in case we aborted and resumed another + // root. + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + resetHydrationState(); + } + return workInProgress.child; +} + +function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { + pushHostContext(workInProgress); + + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var nextProps = workInProgress.pendingProps; + var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; + + var nextChildren = nextProps.children; + var isDirectTextChild = shouldSetTextContent(type, nextProps); + + if (isDirectTextChild) { + // We special case a direct text child of a host node. This is a common + // case. We won't handle it as a reified child. We will instead handle + // this in the host environment that also have access to this prop. That + // avoids allocating another HostText fiber and traversing it. + nextChildren = null; + } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { + // If we're switching from a direct text child to a normal child, or to + // empty, we need to schedule the text content to be reset. + workInProgress.effectTag |= ContentReset; + } + + markRef(current$$1, workInProgress); + + // Check the host config to see if the children are offscreen/hidden. + if ( + renderExpirationTime !== Never && + workInProgress.mode & ConcurrentMode && + shouldDeprioritizeSubtree(type, nextProps) + ) { + // Schedule this fiber to re-render at offscreen priority. Then bailout. + workInProgress.expirationTime = workInProgress.childExpirationTime = Never; + return null; + } + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateHostText(current$$1, workInProgress) { + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + return null; +} + +function mountLazyComponent( + _current, + workInProgress, + elementType, + updateExpirationTime, + renderExpirationTime +) { + if (_current !== null) { + // An lazy component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + // We can't start a User Timing measurement with correct label yet. + // Cancel and resume right after we know the tag. + cancelWorkTimer(workInProgress); + var Component = readLazyComponentType(elementType); + // Store the unwrapped component in the type. + workInProgress.type = Component; + var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); + startWorkTimer(workInProgress); + var resolvedProps = resolveDefaultProps(Component, props); + var child = void 0; + switch (resolvedTag) { + case FunctionComponent: { + { + validateFunctionComponentInDev(workInProgress, Component); + } + child = updateFunctionComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ClassComponent: { + child = updateClassComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ForwardRef: { + child = updateForwardRef( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case MemoComponent: { + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = Component.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + resolvedProps, // Resolved for outer only + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + child = updateMemoComponent( + null, + workInProgress, + Component, + resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too + updateExpirationTime, + renderExpirationTime + ); + break; + } + default: { + var hint = ""; + { + if ( + Component !== null && + typeof Component === "object" && + Component.$$typeof === REACT_LAZY_TYPE + ) { + hint = " Did you wrap a component in React.lazy() more than once?"; + } + } + // This message intentionally doesn't mention ForwardRef or MemoComponent + // because the fact that it's a separate type of work is an + // implementation detail. + (function() { + { + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + Component + + ". Lazy element type must resolve to a class or function." + + hint + ); + } + })(); + } + } + return child; +} + +function mountIncompleteClassComponent( + _current, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (_current !== null) { + // An incomplete component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + // Promote the fiber to a class and try rendering again. + workInProgress.tag = ClassComponent; + + // The rest of this function is a fork of `updateClassComponent` + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); +} + +function mountIndeterminateComponent( + _current, + workInProgress, + Component, + renderExpirationTime +) { + if (_current !== null) { + // An indeterminate component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); + var context = getMaskedContext(workInProgress, unmaskedContext); + + prepareToReadContext(workInProgress, renderExpirationTime); + + var value = void 0; + + { + if ( + Component.prototype && + typeof Component.prototype.render === "function" + ) { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutBadClass[componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + + "This is likely to cause errors. Change %s to extend React.Component instead.", + componentName, + componentName + ); + didWarnAboutBadClass[componentName] = true; + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } + + ReactCurrentOwner$3.current = workInProgress; + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + { + var _componentName = getComponentName(Component) || "Unknown"; + if (!didWarnAboutModulePatternComponent[_componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to be a function component that returns a class instance. " + + "Change %s to a class that extends React.Component instead. " + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + + "cannot be called with `new` by React.", + _componentName, + _componentName, + _componentName + ); + didWarnAboutModulePatternComponent[_componentName] = true; + } + } + + // Proceed under the assumption that this is a class instance + workInProgress.tag = ClassComponent; + + // Throw out any hooks that were used. + resetHooks(); + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = false; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + workInProgress.memoizedState = + value.state !== null && value.state !== undefined ? value.state : null; + + var getDerivedStateFromProps = Component.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + props + ); + } + + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, Component, props, renderExpirationTime); + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); + } else { + // Proceed under the assumption that this is a function component + workInProgress.tag = FunctionComponent; + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + } + } + reconcileChildren(null, workInProgress, value, renderExpirationTime); + { + validateFunctionComponentInDev(workInProgress, Component); + } + return workInProgress.child; + } +} + +function validateFunctionComponentInDev(workInProgress, Component) { + if (Component) { + !!Component.childContextTypes + ? warningWithoutStack$1( + false, + "%s(...): childContextTypes cannot be defined on a function component.", + Component.displayName || Component.name || "Component" + ) + : void 0; + } + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + + var warningKey = ownerName || workInProgress._debugID || ""; + var debugSource = workInProgress._debugSource; + if (debugSource) { + warningKey = debugSource.fileName + ":" + debugSource.lineNumber; + } + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; + warning$1( + false, + "Function components cannot be given refs. " + + "Attempts to access this ref will fail. " + + "Did you mean to use React.forwardRef()?%s", + info + ); + } + } + + if (typeof Component.getDerivedStateFromProps === "function") { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) { + warningWithoutStack$1( + false, + "%s: Function components do not support getDerivedStateFromProps.", + componentName + ); + didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true; + } + } + + if ( + typeof Component.contextType === "object" && + Component.contextType !== null + ) { + var _componentName2 = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName2]) { + warningWithoutStack$1( + false, + "%s: Function components do not support contextType.", + _componentName2 + ); + didWarnAboutContextTypeOnFunctionComponent[_componentName2] = true; + } + } +} + +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode; + var nextProps = workInProgress.pendingProps; + + { + if (shouldSuspend(workInProgress)) { + workInProgress.effectTag |= DidCapture; + } + } + + // We should attempt to render the primary children unless this boundary + // already suspended during this render (`alreadyCaptured` is true). + var nextState = workInProgress.memoizedState; + + var nextDidTimeout = void 0; + if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This is the first attempt. + nextState = null; + nextDidTimeout = false; + } else { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + nextState = { + fallbackExpirationTime: + nextState !== null ? nextState.fallbackExpirationTime : NoWork + }; + nextDidTimeout = true; + workInProgress.effectTag &= ~DidCapture; + } + + { + if ("maxDuration" in nextProps) { + if (!didWarnAboutMaxDuration) { + didWarnAboutMaxDuration = true; + warning$1( + false, + "maxDuration has been removed from React. " + + "Remove the maxDuration prop." + ); + } + } + } + + // This next part is a bit confusing. If the children timeout, we switch to + // showing the fallback children in place of the "primary" children. + // However, we don't want to delete the primary children because then their + // state will be lost (both the React state and the host state, e.g. + // uncontrolled form inputs). Instead we keep them mounted and hide them. + // Both the fallback children AND the primary children are rendered at the + // same time. Once the primary children are un-suspended, we can delete + // the fallback children — don't need to preserve their state. + // + // The two sets of children are siblings in the host environment, but + // semantically, for purposes of reconciliation, they are two separate sets. + // So we store them using two fragment fibers. + // + // However, we want to avoid allocating extra fibers for every placeholder. + // They're only necessary when the children time out, because that's the + // only time when both sets are mounted. + // + // So, the extra fragment fibers are only used if the children time out. + // Otherwise, we render the primary children directly. This requires some + // custom reconciliation logic to preserve the state of the primary + // children. It's essentially a very basic form of re-parenting. + + // `child` points to the child fiber. In the normal case, this is the first + // fiber of the primary children set. In the timed-out case, it's a + // a fragment fiber containing the primary children. + var child = void 0; + // `next` points to the next fiber React should render. In the normal case, + // it's the same as `child`: the first fiber of the primary children set. + // In the timed-out case, it's a fragment fiber containing the *fallback* + // children -- we skip over the primary children entirely. + var next = void 0; + if (current$$1 === null) { + if (enableSuspenseServerRenderer) { + // If we're currently hydrating, try to hydrate this boundary. + // But only if this has a fallback. + if (nextProps.fallback !== undefined) { + tryToClaimNextHydratableInstance(workInProgress); + // This could've changed the tag if this was a dehydrated suspense component. + if (workInProgress.tag === DehydratedSuspenseComponent) { + return updateDehydratedSuspenseComponent( + null, + workInProgress, + renderExpirationTime + ); + } + } + } + + // This is the initial mount. This branch is pretty simple because there's + // no previous state that needs to be preserved. + if (nextDidTimeout) { + // Mount separate fragments for primary and fallback children. + var nextFallbackChildren = nextProps.fallback; + var primaryChildFragment = createFiberFromFragment( + null, + mode, + NoWork, + null + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var progressedState = workInProgress.memoizedState; + var progressedPrimaryChild = + progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + primaryChildFragment.child = progressedPrimaryChild; + } + + var fallbackChildFragment = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + primaryChildFragment.sibling = fallbackChildFragment; + child = primaryChildFragment; + // Skip the primary children, and continue working on the + // fallback children. + next = fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // Mount the primary children without an intermediate fragment fiber. + var nextPrimaryChildren = nextProps.children; + child = next = mountChildFibers( + workInProgress, + null, + nextPrimaryChildren, + renderExpirationTime + ); + } + } else { + // This is an update. This branch is more complicated because we need to + // ensure the state of the primary children is preserved. + var prevState = current$$1.memoizedState; + var prevDidTimeout = prevState !== null; + if (prevDidTimeout) { + // The current tree already timed out. That means each child set is + var currentPrimaryChildFragment = current$$1.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + if (nextDidTimeout) { + // Still timed out. Reuse the current primary children by cloning + // its fragment. We're going to skip over these entirely. + var _nextFallbackChildren = nextProps.fallback; + var _primaryChildFragment = createWorkInProgress( + currentPrimaryChildFragment, + currentPrimaryChildFragment.pendingProps, + NoWork + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState = workInProgress.memoizedState; + var _progressedPrimaryChild = + _progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { + _primaryChildFragment.child = _progressedPrimaryChild; + } + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var treeBaseDuration = 0; + var hiddenChild = _primaryChildFragment.child; + while (hiddenChild !== null) { + treeBaseDuration += hiddenChild.treeBaseDuration; + hiddenChild = hiddenChild.sibling; + } + _primaryChildFragment.treeBaseDuration = treeBaseDuration; + } + + // Clone the fallback child fragment, too. These we'll continue + // working on. + var _fallbackChildFragment = (_primaryChildFragment.sibling = createWorkInProgress( + currentFallbackChildFragment, + _nextFallbackChildren, + currentFallbackChildFragment.expirationTime + )); + child = _primaryChildFragment; + _primaryChildFragment.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // No longer suspended. Switch back to showing the primary children, + // and remove the intermediate fragment fiber. + var _nextPrimaryChildren = nextProps.children; + var currentPrimaryChild = currentPrimaryChildFragment.child; + var primaryChild = reconcileChildFibers( + workInProgress, + currentPrimaryChild, + _nextPrimaryChildren, + renderExpirationTime + ); + + // If this render doesn't suspend, we need to delete the fallback + // children. Wait until the complete phase, after we've confirmed the + // fallback is no longer needed. + // TODO: Would it be better to store the fallback fragment on + // the stateNode? + + // Continue rendering the children, like we normally do. + child = next = primaryChild; + } + } else { + // The current tree has not already timed out. That means the primary + // children are not wrapped in a fragment fiber. + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + // Timed out. Wrap the children in a fragment fiber to keep them + // separate from the fallback children. + var _nextFallbackChildren2 = nextProps.fallback; + var _primaryChildFragment2 = createFiberFromFragment( + // It shouldn't matter what the pending props are because we aren't + // going to render this fragment. + null, + mode, + NoWork, + null + ); + _primaryChildFragment2.child = _currentPrimaryChild; + + // Even though we're creating a new fiber, there are no new children, + // because we're reusing an already mounted tree. So we don't need to + // schedule a placement. + // primaryChildFragment.effectTag |= Placement; + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState2 = workInProgress.memoizedState; + var _progressedPrimaryChild2 = + _progressedState2 !== null + ? workInProgress.child.child + : workInProgress.child; + _primaryChildFragment2.child = _progressedPrimaryChild2; + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var _treeBaseDuration = 0; + var _hiddenChild = _primaryChildFragment2.child; + while (_hiddenChild !== null) { + _treeBaseDuration += _hiddenChild.treeBaseDuration; + _hiddenChild = _hiddenChild.sibling; + } + _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; + } + + // Create a fragment from the fallback children, too. + var _fallbackChildFragment2 = (_primaryChildFragment2.sibling = createFiberFromFragment( + _nextFallbackChildren2, + mode, + renderExpirationTime, + null + )); + _fallbackChildFragment2.effectTag |= Placement; + child = _primaryChildFragment2; + _primaryChildFragment2.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment2; + child.return = next.return = workInProgress; + } else { + // Still haven't timed out. Continue rendering the children, like we + // normally do. + var _nextPrimaryChildren2 = nextProps.children; + next = child = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + _nextPrimaryChildren2, + renderExpirationTime + ); + } + } + workInProgress.stateNode = current$$1.stateNode; + } + + workInProgress.memoizedState = nextState; + workInProgress.child = child; + return next; +} + +function retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime +) { + // Detach from the current dehydrated boundary. + current$$1.alternate = null; + workInProgress.alternate = null; + + // Insert a deletion in the effect list. + var returnFiber = workInProgress.return; + (function() { + if (!(returnFiber !== null)) { + throw ReactError( + "Suspense boundaries are never on the root. This is probably a bug in React." + ); + } + })(); + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = current$$1; + returnFiber.lastEffect = current$$1; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = current$$1; + } + current$$1.nextEffect = null; + current$$1.effectTag = Deletion; + + // Upgrade this work in progress to a real Suspense component. + workInProgress.tag = SuspenseComponent; + workInProgress.stateNode = null; + workInProgress.memoizedState = null; + // This is now an insertion. + workInProgress.effectTag |= Placement; + // Retry as a real Suspense component. + return updateSuspenseComponent(null, workInProgress, renderExpirationTime); +} + +function updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var suspenseInstance = workInProgress.stateNode; + if (current$$1 === null) { + // During the first pass, we'll bail out and not drill into the children. + // Instead, we'll leave the content in place and try to hydrate it later. + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This is a client-only boundary. Since we won't get any content from the server + // for this, we need to schedule that at a higher priority based on when it would + // have timed out. In theory we could render it in this pass but it would have the + // wrong priority associated with it and will prevent hydration of parent path. + // Instead, we'll leave work left on it to render it in a separate commit. + + // TODO This time should be the time at which the server rendered response that is + // a parent to this boundary was displayed. However, since we currently don't have + // a protocol to transfer that time, we'll just estimate it by using the current + // time. This will mean that Suspense timeouts are slightly shifted to later than + // they should be. + var serverDisplayTime = requestCurrentTime(); + // Schedule a normal pri update to render this content. + workInProgress.expirationTime = computeAsyncExpiration(serverDisplayTime); + } else { + // We'll continue hydrating the rest at offscreen priority since we'll already + // be showing the right content coming from the server, it is no rush. + workInProgress.expirationTime = Never; + } + return null; + } + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Leave the existing children in place. + // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? + workInProgress.child = null; + return null; + } + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This boundary is in a permanent fallback state. In this case, we'll never + // get an update and we'll never be able to hydrate the final content. Let's just try the + // client side render instead. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } + // We use childExpirationTime to indicate that a child might depend on context, so if + // any context has changed, we need to treat is as if the input might have changed. + var hasContextChanged$$1 = + current$$1.childExpirationTime >= renderExpirationTime; + if (didReceiveUpdate || hasContextChanged$$1) { + // This boundary has changed since the first render. This means that we are now unable to + // hydrate it. We might still be able to hydrate it using an earlier expiration time but + // during this render we can't. Instead, we're going to delete the whole subtree and + // instead inject a new real Suspense boundary to take its place, which may render content + // or fallback. The real Suspense boundary will suspend for a while so we have some time + // to ensure it can produce real content, but all state and pending events will be lost. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } else if (isSuspenseInstancePending(suspenseInstance)) { + // This component is still pending more data from the server, so we can't hydrate its + // content. We treat it as if this component suspended itself. It might seem as if + // we could just try to render it client-side instead. However, this will perform a + // lot of unnecessary work and is unlikely to complete since it often will suspend + // on missing data anyway. Additionally, the server might be able to render more + // than we can on the client yet. In that case we'd end up with more fallback states + // on the client than if we just leave it alone. If the server times out or errors + // these should update this boundary to the permanent Fallback state instead. + // Mark it as having captured (i.e. suspended). + workInProgress.effectTag |= DidCapture; + // Leave the children in place. I.e. empty. + workInProgress.child = null; + // Register a callback to retry this boundary once the server has sent the result. + registerSuspenseInstanceRetry( + suspenseInstance, + retryTimedOutBoundary.bind(null, current$$1) + ); + return null; + } else { + // This is the first attempt. + reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; + } +} + +function updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + if (current$$1 === null) { + // Portals are special because we don't append the children during mount + // but at commit. Therefore we need to track insertions which the normal + // flow doesn't do during mount. This doesn't happen at the root because + // the root always starts with a "current" with a null child. + // TODO: Consider unifying this with how the root works. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + return workInProgress.child; +} + +function updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime +) { + var providerType = workInProgress.type; + var context = providerType._context; + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = newProps.value; + + { + var providerPropTypes = workInProgress.type.propTypes; + + if (providerPropTypes) { + checkPropTypes( + providerPropTypes, + newProps, + "prop", + "Context.Provider", + getCurrentFiberStackInDev + ); + } + } + + pushProvider(workInProgress, newValue); + + if (oldProps !== null) { + var oldValue = oldProps.value; + var changedBits = calculateChangedBits(context, newValue, oldValue); + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children && !hasContextChanged()) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } + } + + var newChildren = newProps.children; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +var hasWarnedAboutUsingContextAsConsumer = false; + +function updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime +) { + var context = workInProgress.type; + // The logic below for Context differs depending on PROD or DEV mode. In + // DEV mode, we create a separate object for Context.Consumer that acts + // like a proxy to Context. This proxy object adds unnecessary code in PROD + // so we use the old behaviour (Context.Consumer references Context) to + // reduce size and overhead. The separate object references context via + // a property called "_context", which also gives us the ability to check + // in DEV mode if this property exists or not and warn if it does not. + { + if (context._context === undefined) { + // This may be because it's a Context (rather than a Consumer). + // Or it may be because it's older React where they're the same thing. + // We only want to warn if we're sure it's a new React. + if (context !== context.Consumer) { + if (!hasWarnedAboutUsingContextAsConsumer) { + hasWarnedAboutUsingContextAsConsumer = true; + warning$1( + false, + "Rendering directly is not supported and will be removed in " + + "a future major release. Did you mean to render instead?" + ); + } + } + } else { + context = context._context; + } + } + var newProps = workInProgress.pendingProps; + var render = newProps.children; + + { + !(typeof render === "function") + ? warningWithoutStack$1( + false, + "A context consumer was rendered with multiple children, or a child " + + "that isn't a function. A context consumer expects a single child " + + "that is a function. If you did pass a function, make sure there " + + "is no trailing or leading whitespace around it." + ) + : void 0; + } + + prepareToReadContext(workInProgress, renderExpirationTime); + var newValue = readContext(context, newProps.unstable_observedBits); + var newChildren = void 0; + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + newChildren = render(newValue); + setCurrentPhase(null); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime +) { + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + pushHostContextForEventComponent(workInProgress); + return workInProgress.child; +} + +function updateEventTarget(current$$1, workInProgress, renderExpirationTime) { + var type = workInProgress.type.type; + var nextProps = workInProgress.pendingProps; + var eventTargetChild = getEventTargetChildElement(type, nextProps); + + { + !(nextProps.children == null) + ? warning$1(false, "Event targets should not have children.") + : void 0; + } + if (eventTargetChild !== null) { + var child = (workInProgress.child = createFiberFromTypeAndProps( + eventTargetChild.type, + null, + eventTargetChild.props, + null, + workInProgress.mode, + renderExpirationTime + )); + child.return = workInProgress; + + if (current$$1 === null || current$$1.child === null) { + child.effectTag = Placement; + } + } else { + reconcileChildren(current$$1, workInProgress, null, renderExpirationTime); + } + pushHostContextForEventTarget(workInProgress); + return workInProgress.child; +} + +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} + +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + cancelWorkTimer(workInProgress); + + if (current$$1 !== null) { + // Reuse previous context list + workInProgress.contextDependencies = current$$1.contextDependencies; + } + + if (enableProfilerTimer) { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(workInProgress); + } + + // Check if the children have any pending work. + var childExpirationTime = workInProgress.childExpirationTime; + if (childExpirationTime < renderExpirationTime) { + // The children don't have any work either. We can skip them. + // TODO: Once we add back resuming, we should check if the children are + // a work-in-progress set. If so, we need to transfer their effects. + return null; + } else { + // This fiber doesn't have work, but its subtree does. Clone the child + // fibers and continue. + cloneChildFibers(current$$1, workInProgress); + return workInProgress.child; + } +} + +function beginWork$1(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + + if (current$$1 !== null) { + var oldProps = current$$1.memoizedProps; + var newProps = workInProgress.pendingProps; + + if (oldProps !== newProps || hasContextChanged()) { + // If props or context changed, mark the fiber as having performed work. + // This may be unset if the props are determined to be equal later (memo). + didReceiveUpdate = true; + } else if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = false; + // This fiber does not have any pending work. Bailout without entering + // the begin phase. There's still some bookkeeping we that needs to be done + // in this optimized path, mostly pushing stuff onto the stack. + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + resetHydrationState(); + break; + case HostComponent: + pushHostContext(workInProgress); + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); + } + break; + } + case HostPortal: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case ContextProvider: { + var newValue = workInProgress.memoizedProps.value; + pushProvider(workInProgress, newValue); + break; + } + case Profiler: + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + break; + case SuspenseComponent: { + var state = workInProgress.memoizedState; + var didTimeout = state !== null; + if (didTimeout) { + // If this boundary is currently timed out, we need to decide + // whether to retry the primary children, or to skip over it and + // go straight to the fallback. Check the priority of the primary + var primaryChildFragment = workInProgress.child; + var primaryChildExpirationTime = + primaryChildFragment.childExpirationTime; + if ( + primaryChildExpirationTime !== NoWork && + primaryChildExpirationTime >= renderExpirationTime + ) { + // The primary children have pending work. Use the normal path + // to attempt to render the primary children again. + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } else { + // The primary children do not have pending work with sufficient + // priority. Bailout. + var child = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; + } else { + return null; + } + } + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // We know that this component will suspend again because if it has + // been unsuspended it has committed as a regular Suspense component. + // If it needs to be retried, it should have work scheduled on it. + workInProgress.effectTag |= DidCapture; + } + break; + } + case EventComponent: + if (enableEventAPI) { + pushHostContextForEventComponent(workInProgress); + } + break; + case EventTarget: { + if (enableEventAPI) { + pushHostContextForEventTarget(workInProgress); + } + break; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + didReceiveUpdate = false; + } + + // Before entering the begin phase, clear the expiration time. + workInProgress.expirationTime = NoWork; + + switch (workInProgress.tag) { + case IndeterminateComponent: { + var elementType = workInProgress.elementType; + return mountIndeterminateComponent( + current$$1, + workInProgress, + elementType, + renderExpirationTime + ); + } + case LazyComponent: { + var _elementType = workInProgress.elementType; + return mountLazyComponent( + current$$1, + workInProgress, + _elementType, + updateExpirationTime, + renderExpirationTime + ); + } + case FunctionComponent: { + var _Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = + workInProgress.elementType === _Component + ? unresolvedProps + : resolveDefaultProps(_Component, unresolvedProps); + return updateFunctionComponent( + current$$1, + workInProgress, + _Component, + resolvedProps, + renderExpirationTime + ); + } + case ClassComponent: { + var _Component2 = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; + var _resolvedProps = + workInProgress.elementType === _Component2 + ? _unresolvedProps + : resolveDefaultProps(_Component2, _unresolvedProps); + return updateClassComponent( + current$$1, + workInProgress, + _Component2, + _resolvedProps, + renderExpirationTime + ); + } + case HostRoot: + return updateHostRoot(current$$1, workInProgress, renderExpirationTime); + case HostComponent: + return updateHostComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostText: + return updateHostText(current$$1, workInProgress); + case SuspenseComponent: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostPortal: + return updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case ForwardRef: { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; + var _resolvedProps2 = + workInProgress.elementType === type + ? _unresolvedProps2 + : resolveDefaultProps(type, _unresolvedProps2); + return updateForwardRef( + current$$1, + workInProgress, + type, + _resolvedProps2, + renderExpirationTime + ); + } + case Fragment: + return updateFragment(current$$1, workInProgress, renderExpirationTime); + case Mode: + return updateMode(current$$1, workInProgress, renderExpirationTime); + case Profiler: + return updateProfiler(current$$1, workInProgress, renderExpirationTime); + case ContextProvider: + return updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime + ); + case ContextConsumer: + return updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime + ); + case MemoComponent: { + var _type2 = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; + // Resolve outer props first, then resolve inner props. + var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = _type2.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + _resolvedProps3, // Resolved for outer only + "prop", + getComponentName(_type2), + getCurrentFiberStackInDev + ); + } + } + } + _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); + return updateMemoComponent( + current$$1, + workInProgress, + _type2, + _resolvedProps3, + updateExpirationTime, + renderExpirationTime + ); + } + case SimpleMemoComponent: { + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + } + case IncompleteClassComponent: { + var _Component3 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; + var _resolvedProps4 = + workInProgress.elementType === _Component3 + ? _unresolvedProps4 + : resolveDefaultProps(_Component3, _unresolvedProps4); + return mountIncompleteClassComponent( + current$$1, + workInProgress, + _Component3, + _resolvedProps4, + renderExpirationTime + ); + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + return updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventComponent: { + if (enableEventAPI) { + return updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventTarget: { + if (enableEventAPI) { + return updateEventTarget( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + } + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.effectTag |= Update; +} + +function markRef$1(workInProgress) { + workInProgress.effectTag |= Ref; +} + +var appendAllChildren = void 0; +var updateHostContainer = void 0; +var updateHostComponent$1 = void 0; +var updateHostText$1 = void 0; +if (supportsMutation) { + // Mutation mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + if (node.tag === HostComponent || node.tag === HostText) { + appendInitialChild(parent, node.stateNode); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // If we have an alternate, that means this is an update and we need to + // schedule a side-effect to do the updates. + var oldProps = current.memoizedProps; + if (oldProps === newProps) { + // In mutation mode, this is sufficient for a bailout because + // we won't touch this node even if children changed. + return; + } + + // If we get updated because one of our children updated, we don't + // have newProps so we'll have to reuse them. + // TODO: Split the update API as separate for the props vs. children. + // Even better would be if children weren't special cased at all tho. + var instance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + // TODO: Experiencing an error where oldProps is null. Suggests a host + // component is hitting the resume path. Figure out why. Possibly + // related to `hidden`. + var updatePayload = prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + // TODO: Type this specific to this type of component. + workInProgress.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. All the work is done in commitWork. + if (updatePayload) { + markUpdate(workInProgress); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); + } + }; +} else if (supportsPersistence) { + // Persistent host tree mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendInitialChild(parent, instance); + } else if (node.tag === HostText) { + var _instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance = cloneHiddenTextInstance(_instance, text, node); + } + appendInitialChild(parent, _instance); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildren( + parent, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + // An unfortunate fork of appendAllChildren because we have two different parent types. + var appendAllChildrenToContainer = function( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendChildToContainerChildSet(containerChildSet, instance); + } else if (node.tag === HostText) { + var _instance2 = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance2 = cloneHiddenTextInstance(_instance2, text, node); + } + appendChildToContainerChildSet(containerChildSet, _instance2); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged) { + // No changes, just reuse the existing instance. + } else { + var container = portalOrRoot.containerInfo; + var newChildSet = createContainerChildSet(container); + // If children might have changed, we have to add them all to the set. + appendAllChildrenToContainer(newChildSet, workInProgress, false, false); + portalOrRoot.pendingChildren = newChildSet; + // Schedule an update on the container to swap out the container. + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + var currentInstance = current.stateNode; + var oldProps = current.memoizedProps; + // If there are no effects associated with this node, then none of our children had any updates. + // This guarantees that we can reuse all of them. + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged && oldProps === newProps) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var recyclableInstance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + var updatePayload = null; + if (oldProps !== newProps) { + updatePayload = prepareUpdate( + recyclableInstance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + } + if (childrenUnchanged && updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var newInstance = cloneInstance( + currentInstance, + updatePayload, + type, + oldProps, + newProps, + workInProgress, + childrenUnchanged, + recyclableInstance + ); + if ( + finalizeInitialChildren( + newInstance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = newInstance; + if (childrenUnchanged) { + // If there are no other effects in this tree, we need to flag this node as having one. + // Even though we're not going to use it for anything. + // Otherwise parents won't know that there are new children to propagate upwards. + markUpdate(workInProgress); + } else { + // If children might have changed, we have to add them all to the set. + appendAllChildren(newInstance, workInProgress, false, false); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + if (oldText !== newText) { + // If the text content differs, we'll create a new text instance for it. + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + workInProgress.stateNode = createTextInstance( + newText, + rootContainerInstance, + currentHostContext, + workInProgress + ); + // We'll have to mark it as having an effect, even though we won't use the effect for anything. + // This lets the parents know that at least one of their children has changed. + markUpdate(workInProgress); + } + }; +} else { + // No host operations + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // Noop + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // Noop + }; +} + +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + + switch (workInProgress.tag) { + case IndeterminateComponent: + break; + case LazyComponent: + break; + case SimpleMemoComponent: + case FunctionComponent: + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + break; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var fiberRoot = workInProgress.stateNode; + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } + if (current === null || current.child === null) { + // If we hydrated, pop so that we can delete any remaining children + // that weren't hydrated. + popHydrationState(workInProgress); + // This resets the hacky state to fix isMounted before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag &= ~Placement; + } + updateHostContainer(workInProgress); + break; + } + case HostComponent: { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ); + + if (current.ref !== workInProgress.ref) { + markRef$1(workInProgress); + } + } else { + if (!newProps) { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + break; + } + + var currentHostContext = getHostContext(); + // TODO: Move createInstance to beginWork and keep it on a context + // "stack" as the parent. Then append children as we go in beginWork + // or completeWork depending on we want to add then top->down or + // bottom->up. Top->down is faster in IE11. + var wasHydrated = popHydrationState(workInProgress); + if (wasHydrated) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + if ( + prepareToHydrateHostInstance( + workInProgress, + rootContainerInstance, + currentHostContext + ) + ) { + // If changes to the hydrated node needs to be applied at the + // commit-phase we mark this as such. + markUpdate(workInProgress); + } + } else { + var instance = createInstance( + type, + newProps, + rootContainerInstance, + currentHostContext, + workInProgress + ); + + appendAllChildren(instance, workInProgress, false, false); + + // Certain renderers require commit-time effects for initial mount. + // (eg DOM renderer supports auto-focus for certain elements). + // Make sure such renderers get scheduled for later work. + if ( + finalizeInitialChildren( + instance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = instance; + } + + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef$1(workInProgress); + } + } + break; + } + case HostText: { + var newText = newProps; + if (current && workInProgress.stateNode != null) { + var oldText = current.memoizedProps; + // If we have an alternate, that means this is an update and we need + // to schedule a side-effect to do the updates. + updateHostText$1(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + } + var _rootContainerInstance = getRootHostContainer(); + var _currentHostContext = getHostContext(); + var _wasHydrated = popHydrationState(workInProgress); + if (_wasHydrated) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance, + _currentHostContext, + workInProgress + ); + } + } + break; + } + case ForwardRef: + break; + case SuspenseComponent: { + var nextState = workInProgress.memoizedState; + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Re-render with the fallback children. + workInProgress.expirationTime = renderExpirationTime; + // Do not reset the effect list. + return workInProgress; + } + + var nextDidTimeout = nextState !== null; + var prevDidTimeout = false; + if (current === null) { + // In cases where we didn't find a suitable hydration boundary we never + // downgraded this to a DehydratedSuspenseComponent, but we still need to + // pop the hydration state since we might be inside the insertion tree. + popHydrationState(workInProgress); + } else { + var prevState = current.memoizedState; + prevDidTimeout = prevState !== null; + if (!nextDidTimeout && prevState !== null) { + // We just switched from the fallback to the normal children. + + // Mark the event time of the switching from fallback to normal children, + // based on the start of when we first showed the fallback. This time + var fallbackExpirationTime = prevState.fallbackExpirationTime; + markRenderEventTime(fallbackExpirationTime); + + // Delete the fallback. + // TODO: Would it be better to store the fallback fragment on + // the stateNode during the begin phase? + var currentFallbackChild = current.child.sibling; + if (currentFallbackChild !== null) { + // Deletions go at the beginning of the return fiber's effect list + var first = workInProgress.firstEffect; + if (first !== null) { + workInProgress.firstEffect = currentFallbackChild; + currentFallbackChild.nextEffect = first; + } else { + workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; + currentFallbackChild.nextEffect = null; + } + currentFallbackChild.effectTag = Deletion; + } + } + } + + if (nextDidTimeout && !prevDidTimeout) { + // If this subtreee is running in concurrent mode we can suspend, + // otherwise we won't suspend. + // TODO: This will still suspend a synchronous tree if anything + // in the concurrent tree already suspended during this render. + // This is a known bug. + if ((workInProgress.mode & ConcurrentMode) !== NoContext) { + renderDidSuspend(); + } + } + + if (supportsPersistence) { + // TODO: Only schedule updates if not prevDidTimeout. + if (nextDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. + workInProgress.effectTag |= Update; + } + } + if (supportsMutation) { + // TODO: Only schedule updates if these values are non equal, i.e. it changed. + if (nextDidTimeout || prevDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. In mutation mode, we also need the flag to + // *unhide* children that were previously hidden, so check if the + // is currently timed out, too. + workInProgress.effectTag |= Update; + } + } + break; + } + case Fragment: + break; + case Mode: + break; + case Profiler: + break; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case ContextProvider: + // Pop provider fiber + popProvider(workInProgress); + break; + case ContextConsumer: + break; + case MemoComponent: + break; + case IncompleteClassComponent: { + // Same as class component case. I put it down here so that the tags are + // sequential to ensure this switch is compiled to a jump table. + var _Component = workInProgress.type; + if (isContextProvider(_Component)) { + popContext(workInProgress); + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + if (current === null) { + var _wasHydrated2 = popHydrationState(workInProgress); + (function() { + if (!_wasHydrated2) { + throw ReactError( + "A dehydrated suspense component was completed without a hydrated node. This is probably a bug in React." + ); + } + })(); + skipPastDehydratedSuspenseInstance(workInProgress); + } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This boundary did not suspend so it's now hydrated. + // To handle any future suspense cases, we're going to now upgrade it + // to a Suspense component. We detach it from the existing current fiber. + current.alternate = null; + workInProgress.alternate = null; + workInProgress.tag = SuspenseComponent; + workInProgress.memoizedState = null; + workInProgress.stateNode = null; + } + } + break; + } + case EventComponent: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _rootContainerInstance2 = getRootHostContainer(); + var responder = workInProgress.type.responder; + var eventComponentInstance = workInProgress.stateNode; + + if (eventComponentInstance === null) { + var responderState = null; + if (responder.createInitialState !== undefined) { + responderState = responder.createInitialState(newProps); + } + eventComponentInstance = workInProgress.stateNode = { + currentFiber: workInProgress, + props: newProps, + responder: responder, + rootEventTypes: null, + rootInstance: _rootContainerInstance2, + state: responderState + }; + markUpdate(workInProgress); + } else { + // Update the props on the event component state node + eventComponentInstance.props = newProps; + // Update the root container, so we can properly unmount events at some point + eventComponentInstance.rootInstance = _rootContainerInstance2; + // Update the current fiber + eventComponentInstance.currentFiber = workInProgress; + updateEventComponent(eventComponentInstance); + } + } + break; + } + case EventTarget: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _type = workInProgress.type.type; + var _rootContainerInstance3 = getRootHostContainer(); + var shouldUpdate = handleEventTarget( + _type, + newProps, + _rootContainerInstance3, + workInProgress + ); + // Update the latest props on the stateNode. This is used + // during the event phase to find the most current props. + workInProgress.stateNode.props = newProps; + if (shouldUpdate) { + markUpdate(workInProgress); + } + } + break; + } + default: + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + return null; +} + +function shouldCaptureSuspense(workInProgress) { + // In order to capture, the Suspense component must have a fallback prop. + if (workInProgress.memoizedProps.fallback === undefined) { + return false; + } + // If it was the primary children that just suspended, capture and render the + // fallback. Otherwise, don't capture and bubble to the next boundary. + var nextState = workInProgress.memoizedState; + return nextState === null; +} + +function createCapturedValue(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} + +// Module provided by RN: +/** + * Intercept lifecycle errors and ensure they are shown with the correct stack + * trace within the native redbox component. + */ +function showErrorDialog(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + + var errorToHandle = void 0; + + // Typically Errors are thrown but eg strings or null can be thrown as well. + if (error instanceof Error) { + var message = error.message, + name = error.name; + + var summary = message ? name + ": " + message : name; + + errorToHandle = error; + + try { + errorToHandle.message = + summary + "\n\nThis error is located at:" + componentStack; + } catch (e) {} + } else if (typeof error === "string") { + errorToHandle = new Error( + error + "\n\nThis error is located at:" + componentStack + ); + } else { + errorToHandle = new Error("Unspecified error at:" + componentStack); + } + + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); + + // Return false here to prevent ReactFiberErrorLogger default behavior of + // logging error details to console.error. Calls to console.error are + // automatically routed to the native redbox controller, which we've already + // done above by calling ExceptionsManager. + return false; +} + +function logCapturedError(capturedError) { + var logError = showErrorDialog(capturedError); + + // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + if (logError === false) { + return; + } + + var error = capturedError.error; + { + var componentName = capturedError.componentName, + componentStack = capturedError.componentStack, + errorBoundaryName = capturedError.errorBoundaryName, + errorBoundaryFound = capturedError.errorBoundaryFound, + willRetry = capturedError.willRetry; + + // Browsers support silencing uncaught errors by calling + // `preventDefault()` in window `error` handler. + // We record this information as an expando on the error. + + if (error != null && error._suppressLogging) { + if (errorBoundaryFound && willRetry) { + // The error is recoverable and was silenced. + // Ignore it and don't print the stack addendum. + // This is handy for testing error boundaries without noise. + return; + } + // The error is fatal. Since the silencing might have + // been accidental, we'll surface it anyway. + // However, the browser would have silenced the original error + // so we'll print it first, and then print the stack addendum. + console.error(error); + // For a more detailed description of this block, see: + // https://github.com/facebook/react/pull/13384 + } + + var componentNameMessage = componentName + ? "The above error occurred in the <" + componentName + "> component:" + : "The above error occurred in one of your React components:"; + + var errorBoundaryMessage = void 0; + // errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow. + if (errorBoundaryFound && errorBoundaryName) { + if (willRetry) { + errorBoundaryMessage = + "React will try to recreate this component tree from scratch " + + ("using the error boundary you provided, " + errorBoundaryName + "."); + } else { + errorBoundaryMessage = + "This error was initially handled by the error boundary " + + errorBoundaryName + + ".\n" + + "Recreating the tree from scratch failed so React will unmount the tree."; + } + } else { + errorBoundaryMessage = + "Consider adding an error boundary to your tree to customize error handling behavior.\n" + + "Visit https://fb.me/react-error-boundaries to learn more about error boundaries."; + } + var combinedMessage = + "" + + componentNameMessage + + componentStack + + "\n\n" + + ("" + errorBoundaryMessage); + + // In development, we provide our own message with just the component stack. + // We don't include the original error message and JS stack because the browser + // has already printed it. Even if the application swallows the error, it is still + // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. + console.error(combinedMessage); + } +} + +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + +var PossiblyWeakSet$1 = typeof WeakSet === "function" ? WeakSet : Set; + +function logError(boundary, errorInfo) { + var source = errorInfo.source; + var stack = errorInfo.stack; + if (stack === null && source !== null) { + stack = getStackByFiberInDevAndProd(source); + } + + var capturedError = { + componentName: source !== null ? getComponentName(source.type) : null, + componentStack: stack !== null ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: false, + willRetry: false + }; + + if (boundary !== null && boundary.tag === ClassComponent) { + capturedError.errorBoundary = boundary.stateNode; + capturedError.errorBoundaryName = getComponentName(boundary.type); + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; + } + + try { + logCapturedError(capturedError); + } catch (e) { + // This method must not throw, or React internal state will get messed up. + // If console.error is overridden, or logCapturedError() shows a dialog that throws, + // we want to report this error outside of the normal stack as a last resort. + // https://github.com/facebook/react/issues/13188 + setTimeout(function() { + throw e; + }); + } +} + +var callComponentWillUnmountWithTimer = function(current$$1, instance) { + startPhaseTimer(current$$1, "componentWillUnmount"); + instance.props = current$$1.memoizedProps; + instance.state = current$$1.memoizedState; + instance.componentWillUnmount(); + stopPhaseTimer(); +}; + +// Capture errors so they don't interrupt unmounting. +function safelyCallComponentWillUnmount(current$$1, instance) { + { + invokeGuardedCallback( + null, + callComponentWillUnmountWithTimer, + null, + current$$1, + instance + ); + if (hasCaughtError()) { + var unmountError = clearCaughtError(); + captureCommitPhaseError(current$$1, unmountError); + } + } +} + +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (ref !== null) { + if (typeof ref === "function") { + { + invokeGuardedCallback(null, ref, null, null); + if (hasCaughtError()) { + var refError = clearCaughtError(); + captureCommitPhaseError(current$$1, refError); + } + } + } else { + ref.current = null; + } + } +} + +function safelyCallDestroy(current$$1, destroy) { + { + invokeGuardedCallback(null, destroy, null); + if (hasCaughtError()) { + var error = clearCaughtError(); + captureCommitPhaseError(current$$1, error); + } + } +} + +function commitBeforeMutationLifeCycles(current$$1, finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); + return; + } + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var instance = finishedWork.stateNode; + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + var snapshot = instance.getSnapshotBeforeUpdate( + finishedWork.elementType === finishedWork.type + ? prevProps + : resolveDefaultProps(finishedWork.type, prevProps), + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); + warningWithoutStack$1( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork.type) + ); + } + } + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case IncompleteClassComponent: + case EventTarget: + // Nothing to do for these component types + return; + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + // Unmount + var destroy = effect.destroy; + effect.destroy = undefined; + if (destroy !== undefined) { + destroy(); + } + } + if ((effect.tag & mountTag) !== NoEffect$1) { + // Mount + var create = effect.create; + effect.destroy = create(); + + { + var _destroy = effect.destroy; + if (_destroy !== undefined && typeof _destroy !== "function") { + var addendum = void 0; + if (_destroy === null) { + addendum = + " You returned null. If your effect does not require clean " + + "up, return undefined (or nothing)."; + } else if (typeof _destroy.then === "function") { + addendum = + "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " + + "Instead, write the async function inside your effect " + + "and call it immediately:\n\n" + + "useEffect(() => {\n" + + " async function fetchData() {\n" + + " // You can await here\n" + + " const response = await MyAPI.getData(someId);\n" + + " // ...\n" + + " }\n" + + " fetchData();\n" + + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + + "Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching"; + } else { + addendum = " You returned: " + _destroy; + } + warningWithoutStack$1( + false, + "An effect function must not return anything besides a function, " + + "which is used for clean-up.%s%s", + addendum, + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + } + effect = effect.next; + } while (effect !== firstEffect); + } +} + +function commitPassiveHookEffects(finishedWork) { + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); +} + +function commitLifeCycles( + finishedRoot, + current$$1, + finishedWork, + committedExpirationTime +) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountLayout, MountLayout, finishedWork); + break; + } + case ClassComponent: { + var instance = finishedWork.stateNode; + if (finishedWork.effectTag & Update) { + if (current$$1 === null) { + startPhaseTimer(finishedWork, "componentDidMount"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidMount(); + stopPhaseTimer(); + } else { + var prevProps = + finishedWork.elementType === finishedWork.type + ? current$$1.memoizedProps + : resolveDefaultProps( + finishedWork.type, + current$$1.memoizedProps + ); + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "componentDidUpdate"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + stopPhaseTimer(); + } + } + var updateQueue = finishedWork.updateQueue; + if (updateQueue !== null) { + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + commitUpdateQueue( + finishedWork, + updateQueue, + instance, + committedExpirationTime + ); + } + return; + } + case HostRoot: { + var _updateQueue = finishedWork.updateQueue; + if (_updateQueue !== null) { + var _instance = null; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostComponent: + _instance = getPublicInstance(finishedWork.child.stateNode); + break; + case ClassComponent: + _instance = finishedWork.child.stateNode; + break; + } + } + commitUpdateQueue( + finishedWork, + _updateQueue, + _instance, + committedExpirationTime + ); + } + return; + } + case HostComponent: { + var _instance2 = finishedWork.stateNode; + + // Renderers may schedule work to be done after host components are mounted + // (eg DOM renderer may schedule auto-focus for inputs and form controls). + // These effects should only be committed when components are first mounted, + // aka when there is no current/alternate. + if (current$$1 === null && finishedWork.effectTag & Update) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + } + + return; + } + case HostText: { + // We have no life-cycles associated with text. + return; + } + case HostPortal: { + // We have no life-cycles associated with portals. + return; + } + case Profiler: { + if (enableProfilerTimer) { + var onRender = finishedWork.memoizedProps.onRender; + + if (enableSchedulerTracing) { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime(), + finishedRoot.memoizedInteractions + ); + } else { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime() + ); + } + } + return; + } + case SuspenseComponent: + case IncompleteClassComponent: + return; + case EventTarget: { + if (enableEventAPI) { + var _type = finishedWork.type.type; + var _props = finishedWork.memoizedProps; + var _instance3 = finishedWork.stateNode; + var parentInstance = null; + + var node = finishedWork.return; + // Traverse up the fiber tree until we find the parent host node. + while (node !== null) { + if (node.tag === HostComponent) { + parentInstance = node.stateNode; + break; + } else if (node.tag === HostRoot) { + parentInstance = node.stateNode.containerInfo; + break; + } + node = node.return; + } + (function() { + if (!(parentInstance !== null)) { + throw ReactError( + "This should have a parent host component initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + commitEventTarget(_type, _props, _instance3, parentInstance); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + mountEventComponent(finishedWork.stateNode); + } + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function hideOrUnhideAllChildren(finishedWork, isHidden) { + if (supportsMutation) { + // We only have the top Fiber that was inserted but we need to recurse down its + var node = finishedWork; + while (true) { + if (node.tag === HostComponent) { + var instance = node.stateNode; + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); + } + } else if (node.tag === HostText) { + var _instance4 = node.stateNode; + if (isHidden) { + hideTextInstance(_instance4); + } else { + unhideTextInstance(_instance4, node.memoizedProps); + } + } else if ( + node.tag === SuspenseComponent && + node.memoizedState !== null + ) { + // Found a nested Suspense component that timed out. Skip over the + var fallbackChildFragment = node.child.sibling; + fallbackChildFragment.return = node; + node = fallbackChildFragment; + continue; + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } +} + +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse = void 0; + switch (finishedWork.tag) { + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; + default: + instanceToUse = instance; + } + if (typeof ref === "function") { + ref(instanceToUse); + } else { + { + if (!ref.hasOwnProperty("current")) { + warningWithoutStack$1( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().%s", + getComponentName(finishedWork.type), + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + + ref.current = instanceToUse; + } + } +} + +function commitDetachRef(current$$1) { + var currentRef = current$$1.ref; + if (currentRef !== null) { + if (typeof currentRef === "function") { + currentRef(null); + } else { + currentRef.current = null; + } + } +} + +// User-originating errors (lifecycles and refs) should not interrupt +// deletion, so don't let them throw. Host-originating errors should +// interrupt deletion, so it's okay +function commitUnmount(current$$1) { + onCommitUnmount(current$$1); + + switch (current$$1.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + var updateQueue = current$$1.updateQueue; + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + var destroy = effect.destroy; + if (destroy !== undefined) { + safelyCallDestroy(current$$1, destroy); + } + effect = effect.next; + } while (effect !== firstEffect); + } + } + break; + } + case ClassComponent: { + safelyDetachRef(current$$1); + var instance = current$$1.stateNode; + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current$$1, instance); + } + return; + } + case HostComponent: { + safelyDetachRef(current$$1); + return; + } + case HostPortal: { + // TODO: this is recursive. + // We are also not using this parent because + // the portal will get pushed immediately. + if (supportsMutation) { + unmountHostComponents(current$$1); + } else if (supportsPersistence) { + emptyPortalContainer(current$$1); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + var eventComponentInstance = current$$1.stateNode; + unmountEventComponent(eventComponentInstance); + current$$1.stateNode = null; + } + } + } +} + +function commitNestedUnmounts(root) { + // While we're inside a removed host node we don't want to call + // removeChild on the inner nodes because they're removed by the top + // call anyway. We also want to call componentWillUnmount on all + // composites before this host node is removed from the tree. Therefore + var node = root; + while (true) { + commitUnmount(node); + // Visit children because they may contain more composite or host nodes. + // Skip portals because commitUnmount() currently visits them recursively. + if ( + node.child !== null && + // If we use mutation we drill down into portals using commitUnmount above. + // If we don't use mutation we drill down into portals here instead. + (!supportsMutation || node.tag !== HostPortal) + ) { + node.child.return = node; + node = node.child; + continue; + } + if (node === root) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === root) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function detachFiber(current$$1) { + // Cut off the return pointers to disconnect it from the tree. Ideally, we + // should clear the child pointer of the parent alternate to let this + // get GC:ed but we don't know which for sure which parent is the current + // one so we'll settle for GC:ing the subtree of this child. This child + // itself will be GC:ed when the parent updates the next time. + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + if (alternate !== null) { + alternate.return = null; + alternate.child = null; + alternate.memoizedState = null; + alternate.updateQueue = null; + } +} + +function emptyPortalContainer(current$$1) { + if (!supportsPersistence) { + return; + } + + var portal = current$$1.stateNode; + var containerInfo = portal.containerInfo; + + var emptyChildSet = createContainerChildSet(containerInfo); + replaceContainerChildren(containerInfo, emptyChildSet); +} + +function commitContainer(finishedWork) { + if (!supportsPersistence) { + return; + } + + switch (finishedWork.tag) { + case ClassComponent: + case HostComponent: + case HostText: + case EventTarget: + case EventComponent: { + return; + } + case HostRoot: + case HostPortal: { + var portalOrRoot = finishedWork.stateNode; + var containerInfo = portalOrRoot.containerInfo, + _pendingChildren = portalOrRoot.pendingChildren; + + replaceContainerChildren(containerInfo, _pendingChildren); + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function getHostParentFiber(fiber) { + var parent = fiber.return; + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + parent = parent.return; + } + (function() { + { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function isHostParent(fiber) { + return ( + fiber.tag === HostComponent || + fiber.tag === HostRoot || + fiber.tag === HostPortal + ); +} + +function getHostSibling(fiber) { + // We're going to search forward into the tree until we find a sibling host + // node. Unfortunately, if multiple insertions are done in a row we have to + // search past them. This leads to exponential search for the next sibling. + var node = fiber; + siblings: while (true) { + // If we didn't find anything, let's try the next sibling. + while (node.sibling === null) { + if (node.return === null || isHostParent(node.return)) { + // If we pop out of the root or hit the parent the fiber we are the + // last sibling. + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + while ( + node.tag !== HostComponent && + node.tag !== HostText && + node.tag !== DehydratedSuspenseComponent + ) { + // If it is not host node and, we might have a host node inside it. + // Try to search down until we find one. + if (node.effectTag & Placement) { + // If we don't have a child, try the siblings instead. + continue siblings; + } + // If we don't have a child, try the siblings instead. + // We also skip portals because they are not part of this host tree. + if (node.child === null || node.tag === HostPortal) { + continue siblings; + } else { + node.child.return = node; + node = node.child; + } + } + // Check if this host node is stable or about to be placed. + if (!(node.effectTag & Placement)) { + // Found it! + return node.stateNode; + } + } +} + +function commitPlacement(finishedWork) { + if (!supportsMutation) { + return; + } + + // Recursively insert all host nodes into the parent. + var parentFiber = getHostParentFiber(finishedWork); + + // Note: these two variables *must* always be updated together. + var parent = void 0; + var isContainer = void 0; + + switch (parentFiber.tag) { + case HostComponent: + parent = parentFiber.stateNode; + isContainer = false; + break; + case HostRoot: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + case HostPortal: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + default: + (function() { + { + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + if (parentFiber.effectTag & ContentReset) { + // Reset the text content of the parent before doing any insertions + parentFiber.effectTag &= ~ContentReset; + } + + var before = getHostSibling(finishedWork); + // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + var node = finishedWork; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + var stateNode = node.stateNode; + if (before) { + if (isContainer) { + insertInContainerBefore(parent, stateNode, before); + } else { + insertBefore(parent, stateNode, before); + } + } else { + if (isContainer) { + appendChildToContainer(parent, stateNode); + } else { + appendChild(parent, stateNode); + } + } + } else if (node.tag === HostPortal) { + // If the insertion itself is a portal, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function unmountHostComponents(current$$1) { + // We only have the top Fiber that was deleted but we need to recurse down its + var node = current$$1; + + // Each iteration, currentParent is populated with node's host parent if not + // currentParentIsValid. + var currentParentIsValid = false; + + // Note: these two variables *must* always be updated together. + var currentParent = void 0; + var currentParentIsContainer = void 0; + + while (true) { + if (!currentParentIsValid) { + var parent = node.return; + findParent: while (true) { + (function() { + if (!(parent !== null)) { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + switch (parent.tag) { + case HostComponent: + currentParent = parent.stateNode; + currentParentIsContainer = false; + break findParent; + case HostRoot: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + case HostPortal: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + } + parent = parent.return; + } + currentParentIsValid = true; + } + + if (node.tag === HostComponent || node.tag === HostText) { + commitNestedUnmounts(node); + // After all the children have unmounted, it is now safe to remove the + // node from the tree. + if (currentParentIsContainer) { + removeChildFromContainer(currentParent, node.stateNode); + } else { + removeChild(currentParent, node.stateNode); + } + // Don't visit children because we already visited them. + } else if ( + enableSuspenseServerRenderer && + node.tag === DehydratedSuspenseComponent + ) { + // Delete the dehydrated suspense boundary and all of its content. + if (currentParentIsContainer) { + clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); + } else { + clearSuspenseBoundary(currentParent, node.stateNode); + } + } else if (node.tag === HostPortal) { + if (node.child !== null) { + // When we go into a portal, it becomes the parent to remove from. + // We will reassign it back when we pop the portal on the way up. + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = true; + // Visit children because portals might contain host components. + node.child.return = node; + node = node.child; + continue; + } + } else { + commitUnmount(node); + // Visit children because we may find more host components below. + if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === current$$1) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === current$$1) { + return; + } + node = node.return; + if (node.tag === HostPortal) { + // When we go out of the portal, we need to restore the parent. + // Since we don't keep a stack of them, we will search for it. + currentParentIsValid = false; + } + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function commitDeletion(current$$1) { + if (supportsMutation) { + // Recursively delete all host nodes from the parent. + // Detach refs and call componentWillUnmount() on the whole subtree. + unmountHostComponents(current$$1); + } else { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitNestedUnmounts(current$$1); + } + detachFiber(current$$1); +} + +function commitWork(current$$1, finishedWork) { + if (!supportsMutation) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + } + + commitContainer(finishedWork); + return; + } + + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case ClassComponent: { + return; + } + case HostComponent: { + var instance = finishedWork.stateNode; + if (instance != null) { + // Commit the work prepared earlier. + var newProps = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldProps = + current$$1 !== null ? current$$1.memoizedProps : newProps; + var type = finishedWork.type; + // TODO: Type the updateQueue to be specific to host components. + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + if (updatePayload !== null) { + commitUpdate( + instance, + updatePayload, + type, + oldProps, + newProps, + finishedWork + ); + } + } + return; + } + case HostText: { + (function() { + if (!(finishedWork.stateNode !== null)) { + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var textInstance = finishedWork.stateNode; + var newText = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldText = current$$1 !== null ? current$$1.memoizedProps : newText; + commitTextUpdate(textInstance, oldText, newText); + return; + } + case EventTarget: { + return; + } + case HostRoot: { + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + case IncompleteClassComponent: { + return; + } + case EventComponent: { + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + + var newDidTimeout = void 0; + var primaryChildParent = finishedWork; + if (newState === null) { + newDidTimeout = false; + } else { + newDidTimeout = true; + primaryChildParent = finishedWork.child; + if (newState.fallbackExpirationTime === NoWork) { + // If the children had not already timed out, record the time. + // This is used to compute the elapsed time during subsequent + // attempts to render the children. + // We model this as a normal pri expiration time since that's + // how we infer start time for updates. + newState.fallbackExpirationTime = computeAsyncExpirationNoBucket( + requestCurrentTime() + ); + } + } + + if (supportsMutation && primaryChildParent !== null) { + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + } + + // If this boundary just timed out, then it will have a set of thenables. + // For each thenable, attach a listener so that when it resolves, React + // attempts to re-render the boundary in the primary (pre-timeout) state. + var thenables = finishedWork.updateQueue; + if (thenables !== null) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); + } + thenables.forEach(function(thenable) { + // Memoize using the boundary fiber to prevent redundant listeners. + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + if (!retryCache.has(thenable)) { + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + retryCache.add(thenable); + thenable.then(retry, retry); + } + }); + } +} + +function commitResetTextContent(current$$1) { + if (!supportsMutation) { + return; + } + resetTextContent(current$$1.stateNode); +} + +var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; +var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; + +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + // Unmount the root by rendering null. + update.tag = CaptureUpdate; + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: null }; + var error = errorInfo.value; + update.callback = function() { + onUncaughtError(error); + logError(fiber, errorInfo); + }; + return update; +} + +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + update.tag = CaptureUpdate; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if (typeof getDerivedStateFromError === "function") { + var error = errorInfo.value; + update.payload = function() { + return getDerivedStateFromError(error); + }; + } + + var inst = fiber.stateNode; + if (inst !== null && typeof inst.componentDidCatch === "function") { + update.callback = function callback() { + if (typeof getDerivedStateFromError !== "function") { + // To preserve the preexisting retry behavior of error boundaries, + // we keep track of which ones already failed during this batch. + // This gets reset before we yield back to the browser. + // TODO: Warn in strict mode if getDerivedStateFromError is + // not defined. + markLegacyErrorBoundaryAsFailed(this); + } + var error = errorInfo.value; + var stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: stack !== null ? stack : "" + }); + { + if (typeof getDerivedStateFromError !== "function") { + // If componentDidCatch is the only error boundary method defined, + // then it needs to call setState to recover from errors. + // If no state update is scheduled then the boundary will swallow the error. + !(fiber.expirationTime === Sync) + ? warningWithoutStack$1( + false, + "%s: Error boundaries should implement getDerivedStateFromError(). " + + "In that method, return a state update to display an error message or fallback UI.", + getComponentName(fiber.type) || "Unknown" + ) + : void 0; + } + } + }; + } + return update; +} + +function attachPingListener(root, renderExpirationTime, thenable) { + // Attach a listener to the promise to "ping" the root and retry. But + // only if one does not already exist for the current render expiration + // time (which acts like a "thread ID" here). + var pingCache = root.pingCache; + var threadIDs = void 0; + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } else { + threadIDs = pingCache.get(thenable); + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } + } + if (!threadIDs.has(renderExpirationTime)) { + // Memoize using the thread ID to prevent redundant listeners. + threadIDs.add(renderExpirationTime); + var ping = pingSuspendedRoot.bind( + null, + root, + thenable, + renderExpirationTime + ); + if (enableSchedulerTracing) { + ping = tracing.unstable_wrap(ping); + } + thenable.then(ping, ping); + } +} + +function throwException( + root, + returnFiber, + sourceFiber, + value, + renderExpirationTime +) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + if ( + value !== null && + typeof value === "object" && + typeof value.then === "function" + ) { + // This is a thenable. + var thenable = value; + + // Schedule the nearest Suspense to re-render the timed out view. + var _workInProgress = returnFiber; + do { + if ( + _workInProgress.tag === SuspenseComponent && + shouldCaptureSuspense(_workInProgress) + ) { + // Found the nearest boundary. + + // Stash the promise on the boundary fiber. If the boundary times out, we'll + var thenables = _workInProgress.updateQueue; + if (thenables === null) { + var updateQueue = new Set(); + updateQueue.add(thenable); + _workInProgress.updateQueue = updateQueue; + } else { + thenables.add(thenable); + } + + // If the boundary is outside of concurrent mode, we should *not* + // suspend the commit. Pretend as if the suspended component rendered + // null and keep rendering. In the commit phase, we'll schedule a + // subsequent synchronous update to re-render the Suspense. + // + // Note: It doesn't matter whether the component that suspended was + // inside a concurrent mode tree. If the Suspense is outside of it, we + // should *not* suspend the commit. + if ((_workInProgress.mode & ConcurrentMode) === NoContext) { + _workInProgress.effectTag |= DidCapture; + + // We're going to commit this fiber even though it didn't complete. + // But we shouldn't call any lifecycle methods or callbacks. Remove + // all lifecycle effect tags. + sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); + + if (sourceFiber.tag === ClassComponent) { + var currentSourceFiber = sourceFiber.alternate; + if (currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed class component. For example, we should not call + // componentWillUnmount if it is deleted. + sourceFiber.tag = IncompleteClassComponent; + } else { + // When we try rendering again, we should not reuse the current fiber, + // since it's known to be in an inconsistent state. Use a force updte to + // prevent a bail out. + var update = createUpdate(Sync); + update.tag = ForceUpdate; + enqueueUpdate(sourceFiber, update); + } + } + + // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + sourceFiber.expirationTime = Sync; + + // Exit without suspending. + return; + } + + // Confirmed that the boundary is in a concurrent mode tree. Continue + // with the normal suspend path. + + attachPingListener(root, renderExpirationTime, thenable); + + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } else if ( + enableSuspenseServerRenderer && + _workInProgress.tag === DehydratedSuspenseComponent + ) { + attachPingListener(root, renderExpirationTime, thenable); + + // Since we already have a current fiber, we can eagerly add a retry listener. + var retryCache = _workInProgress.memoizedState; + if (retryCache === null) { + retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); + var current$$1 = _workInProgress.alternate; + (function() { + if (!current$$1) { + throw ReactError( + "A dehydrated suspense boundary must commit before trying to render. This is probably a bug in React." + ); + } + })(); + current$$1.memoizedState = retryCache; + } + // Memoize using the boundary fiber to prevent redundant listeners. + if (!retryCache.has(thenable)) { + retryCache.add(thenable); + var retry = resolveRetryThenable.bind( + null, + _workInProgress, + thenable + ); + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + thenable.then(retry, retry); + } + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } + // This boundary already captured during this render. Continue to the next + // boundary. + _workInProgress = _workInProgress.return; + } while (_workInProgress !== null); + // No boundary was found. Fallthrough to error mode. + // TODO: Use invariant so the message is stripped in prod? + value = new Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n" + + "\n" + + "Add a component higher in the tree to " + + "provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + + // We didn't find a boundary that could handle this type of exception. Start + // over and traverse parent path again, this time treating the exception + // as an error. + renderDidError(); + value = createCapturedValue(value, sourceFiber); + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + var _update = createRootErrorUpdate( + workInProgress, + _errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update); + return; + } + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + (typeof ctor.getDerivedStateFromError === "function" || + (instance !== null && + typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance))) + ) { + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + // Schedule the error boundary to re-render using updated state + var _update2 = createClassErrorUpdate( + workInProgress, + errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update2); + return; + } + break; + default: + break; + } + workInProgress = workInProgress.return; + } while (workInProgress !== null); +} + +function unwindWork(workInProgress, renderExpirationTime) { + switch (workInProgress.tag) { + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + (function() { + if (!((_effectTag & DidCapture) === NoEffect)) { + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + } + })(); + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + case HostComponent: { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } + case SuspenseComponent: { + var _effectTag2 = workInProgress.effectTag; + if (_effectTag2 & ShouldCapture) { + workInProgress.effectTag = (_effectTag2 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + return null; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // TODO: popHydrationState + var _effectTag3 = workInProgress.effectTag; + if (_effectTag3 & ShouldCapture) { + workInProgress.effectTag = + (_effectTag3 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + } + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + case EventComponent: + case EventTarget: + if (enableEventAPI) { + popHostContext(workInProgress); + } + return null; + default: + return null; + } +} + +function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + var childContextTypes = interruptedWork.type.childContextTypes; + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); + } + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } +} + +// TODO: Ahaha Andrew is bad at spellling +// DEV stuff +var ceil = Math.ceil; + +var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; +var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; +var ReactShouldWarnActingUpdates = + ReactSharedInternals.ReactShouldWarnActingUpdates; + +var NotWorking = 0; +var BatchedPhase = 1; +var LegacyUnbatchedPhase = 2; +var RenderPhase = 4; +var CommitPhase = 5; + +var RootIncomplete = 0; +var RootErrored = 1; +var RootSuspended = 2; +var RootCompleted = 3; + +// The phase of work we're currently in +var workPhase = NotWorking; +// The root we're working on +var workInProgressRoot = null; +// The fiber we're working on +var workInProgress = null; +// The expiration time we're rendering +var renderExpirationTime = NoWork; +// Whether to root completed, errored, suspended, etc. +var workInProgressRootExitStatus = RootIncomplete; +// Most recent event time among processed updates during this render. +// This is conceptually a time stamp but expressed in terms of an ExpirationTime +// because we deal mostly with expiration times in the hot path, so this avoids +// the conversion happening in the hot path. +var workInProgressRootMostRecentEventTime = Sync; + +var nextEffect = null; +var hasUncaughtError = false; +var firstUncaughtError = null; +var legacyErrorBoundariesThatAlreadyFailed = null; + +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsExpirationTime = NoWork; + +var rootsWithPendingDiscreteUpdates = null; + +// Use these to prevent an infinite loop of nested updates +var NESTED_UPDATE_LIMIT = 50; +var nestedUpdateCount = 0; +var rootWithNestedUpdates = null; + +var NESTED_PASSIVE_UPDATE_LIMIT = 50; +var nestedPassiveUpdateCount = 0; + +var interruptedBy = null; + +// Expiration times are computed by adding to the current time (the start +// time). However, if two updates are scheduled within the same event, we +// should treat their start times as simultaneous, even if the actual clock +// time has advanced between the first and second call. + +// In other words, because expiration times determine how updates are batched, +// we want all updates of like priority that occur within the same event to +// receive the same expiration time. Otherwise we get tearing. +var currentEventTime = NoWork; + +function requestCurrentTime() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // We're inside React, so it's fine to read the actual time. + return msToExpirationTime(now()); + } + // We're not inside React, so we may be in the middle of a browser event. + if (currentEventTime !== NoWork) { + // Use the same start time for all updates until we enter React again. + return currentEventTime; + } + // This is the first update since React yielded. Compute a new start time. + currentEventTime = msToExpirationTime(now()); + return currentEventTime; +} + +function computeExpirationForFiber(currentTime, fiber) { + if ((fiber.mode & ConcurrentMode) === NoContext) { + return Sync; + } + + if (workPhase === RenderPhase) { + // Use whatever time we're already rendering + return renderExpirationTime; + } + + // Compute an expiration time based on the Scheduler priority. + var expirationTime = void 0; + var priorityLevel = getCurrentPriorityLevel(); + switch (priorityLevel) { + case ImmediatePriority: + expirationTime = Sync; + break; + case UserBlockingPriority: + // TODO: Rename this to computeUserBlockingExpiration + expirationTime = computeInteractiveExpiration(currentTime); + break; + case NormalPriority: + case LowPriority: + // TODO: Handle LowPriority + // TODO: Rename this to... something better. + expirationTime = computeAsyncExpiration(currentTime); + break; + case IdlePriority: + expirationTime = Never; + break; + default: + (function() { + { + throw ReactError("Expected a valid priority level"); + } + })(); + } + + // If we're in the middle of rendering a tree, do not update at the same + // expiration time that is already rendering. + if (workInProgressRoot !== null && expirationTime === renderExpirationTime) { + // This is a trick to move this update into a separate batch + expirationTime -= 1; + } + + return expirationTime; +} + +function scheduleUpdateOnFiber(fiber, expirationTime) { + checkForNestedUpdates(); + warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber); + + var root = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (root === null) { + warnAboutUpdateOnUnmountedFiberInDEV(fiber); + return; + } + + root.pingTime = NoWork; + + checkForInterruption(fiber, expirationTime); + recordScheduleUpdate(); + + if (expirationTime === Sync) { + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. The initial mount of a ReactDOM.render-ed + // root inside of batchedUpdates should be synchronous, but layout updates + // should be deferred until the end of the batch. + var callback = renderRoot(root, Sync, true); + while (callback !== null) { + callback = callback(true); + } + } else { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + if (workPhase === NotWorking) { + // Flush the synchronous work now, wnless we're already working or inside + // a batch. This is intentionally inside scheduleUpdateOnFiber instead of + // scheduleCallbackForFiber to preserve the ability to schedule a callback + // without immediately flushing it. We only do this for user-initated + // updates, to preserve historical behavior of sync mode. + flushImmediateQueue(); + } + } + } else { + // TODO: computeExpirationForFiber also reads the priority. Pass the + // priority as an argument to that function and this one. + var priorityLevel = getCurrentPriorityLevel(); + if (priorityLevel === UserBlockingPriority) { + // This is the result of a discrete event. Track the lowest priority + // discrete update per root so we can flush them early, if needed. + if (rootsWithPendingDiscreteUpdates === null) { + rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]); + } else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root); + if ( + lastDiscreteTime === undefined || + lastDiscreteTime > expirationTime + ) { + rootsWithPendingDiscreteUpdates.set(root, expirationTime); + } + } + } + scheduleCallbackForRoot(root, priorityLevel, expirationTime); + } +} +var scheduleWork = scheduleUpdateOnFiber; + +// This is split into a separate function so we can mark a fiber with pending +// work without treating it as a typical update that originates from an event; +// e.g. retrying a Suspense boundary isn't an update, but it does schedule work +// on a fiber. +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + // Update the source fiber's expiration time + if (fiber.expirationTime < expirationTime) { + fiber.expirationTime = expirationTime; + } + var alternate = fiber.alternate; + if (alternate !== null && alternate.expirationTime < expirationTime) { + alternate.expirationTime = expirationTime; + } + // Walk the parent path to the root and update the child expiration time. + var node = fiber.return; + var root = null; + if (node === null && fiber.tag === HostRoot) { + root = fiber.stateNode; + } else { + while (node !== null) { + alternate = node.alternate; + if (node.childExpirationTime < expirationTime) { + node.childExpirationTime = expirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + if (node.return === null && node.tag === HostRoot) { + root = node.stateNode; + break; + } + node = node.return; + } + } + + if (root !== null) { + // Update the first and last pending expiration times in this root + var firstPendingTime = root.firstPendingTime; + if (expirationTime > firstPendingTime) { + root.firstPendingTime = expirationTime; + } + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime === NoWork || expirationTime < lastPendingTime) { + root.lastPendingTime = expirationTime; + } + } + + return root; +} + +// Use this function, along with runRootCallback, to ensure that only a single +// callback per root is scheduled. It's still possible to call renderRoot +// directly, but scheduling via this function helps avoid excessive callbacks. +// It works by storing the callback node and expiration time on the root. When a +// new callback comes in, it compares the expiration time to determine if it +// should cancel the previous one. It also relies on commitRoot scheduling a +// callback to render the next level, because that means we don't need a +// separate callback per expiration time. +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + var existingCallbackExpirationTime = root.callbackExpirationTime; + if (existingCallbackExpirationTime < expirationTime) { + // New callback has higher priority than the existing one. + var existingCallbackNode = root.callbackNode; + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + root.callbackExpirationTime = expirationTime; + + var options = null; + if (expirationTime !== Sync && expirationTime !== Never) { + var timeout = expirationTimeToMs(expirationTime) - now(); + if (timeout > 5000) { + // Sanity check. Should never take longer than 5 seconds. + // TODO: Add internal warning? + timeout = 5000; + } + options = { timeout: timeout }; + } + + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + options + ); + if ( + enableUserTimingAPI && + expirationTime !== Sync && + workPhase !== RenderPhase && + workPhase !== CommitPhase + ) { + // Scheduled an async callback, and we're not already working. Add an + // entry to the flamegraph that shows we're waiting for a callback + // to fire. + startRequestCallbackTimer(); + } + } + + // Add the current set of interactions to the pending set associated with + // this root. + schedulePendingInteraction(root, expirationTime); +} + +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode; + var continuation = null; + try { + continuation = callback(isSync); + if (continuation !== null) { + return runRootCallback.bind(null, root, continuation); + } else { + return null; + } + } finally { + // If the callback exits without returning a continuation, remove the + // corresponding callback node from the root. Unless the callback node + // has changed, which implies that it was already cancelled by a high + // priority update. + if (continuation === null && prevCallbackNode === root.callbackNode) { + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + } + } +} + +function flushInteractiveUpdates$1() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // Can't synchronously flush interactive updates if React is already + // working. This is currently a no-op. + // TODO: Should we fire a warning? This happens if you synchronously invoke + // an input event inside an effect, like with `element.click()`. + return; + } + flushPendingDiscreteUpdates(); +} + +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + if ( + firstBatch !== null && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ) { + root.finishedWork = root.current.alternate; + root.pendingCommitExpirationTime = expirationTime; + scheduleCallback(NormalPriority, function() { + firstBatch._onComplete(); + return null; + }); + return true; + } else { + return false; + } +} + +function interactiveUpdates$1(fn, a, b, c) { + if (workPhase === NotWorking) { + // TODO: Remove this call. Instead of doing this automatically, the caller + // should explicitly call flushInteractiveUpdates. + flushPendingDiscreteUpdates(); + } + return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c)); +} + +function flushPendingDiscreteUpdates() { + if (rootsWithPendingDiscreteUpdates !== null) { + // For each root with pending discrete updates, schedule a callback to + // immediately flush them. + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + }); + // Now flush the immediate queue. + flushImmediateQueue(); + } +} + +function batchedUpdates$1(fn, a) { + if (workPhase !== NotWorking) { + // We're already working, or inside a batch, so batchedUpdates is a no-op. + return fn(a); + } + workPhase = BatchedPhase; + try { + return fn(a); + } finally { + workPhase = NotWorking; + // Flush the immediate callbacks that were scheduled during this batch + flushImmediateQueue(); + } +} + +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = NoWork; + + var timeoutHandle = root.timeoutHandle; + if (timeoutHandle !== noTimeout) { + // The root previous suspended and scheduled a timeout to commit a fallback + // state. Now that we have additional work, cancel the timeout. + root.timeoutHandle = noTimeout; + // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + cancelTimeout(timeoutHandle); + } + + if (workInProgress !== null) { + var interruptedWork = workInProgress.return; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork.return; + } + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = Sync; + + { + ReactStrictModeWarnings.discardPendingWarnings(); + } +} + +function renderRoot(root, expirationTime, isSync) { + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + + if (enableUserTimingAPI && expirationTime !== Sync) { + var didExpire = isSync; + stopRequestCallbackTimer(didExpire); + } + + if (root.firstPendingTime < expirationTime) { + // If there's no work left at this expiration time, exit immediately. This + // happens when multiple callbacks are scheduled for a single root, but an + // earlier callback flushes the work of a later one. + return null; + } + + if (root.pendingCommitExpirationTime === expirationTime) { + // There's already a pending commit at this expiration time. + root.pendingCommitExpirationTime = NoWork; + return commitRoot.bind(null, root, expirationTime); + } + + flushPassiveEffects(); + + // If the root or expiration time have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) { + prepareFreshStack(root, expirationTime); + startWorkOnPendingInteraction(root, expirationTime); + } + + // If we have a work-in-progress fiber, it means there's still work to do + // in this root. + if (workInProgress !== null) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + if (prevDispatcher === null) { + // The React isomorphic package does not include a default dispatcher. + // Instead the first renderer will lazily attach one, in order to give + // nicer error messages. + prevDispatcher = ContextOnlyDispatcher; + } + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + startWorkLoopTimer(workInProgress); + + // TODO: Fork renderRoot into renderRootSync and renderRootAsync + if (isSync) { + if (expirationTime !== Sync) { + // An async update expired. There may be other expired updates on + // this root. We should render all the expired work in a + // single batch. + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) { + // Restart at the current time. + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + return renderRoot.bind(null, root, currentTime); + } + } + } else { + // Since we know we're in a React event, we can clear the current + // event time. The next update will compute a new event time. + currentEventTime = NoWork; + } + + do { + try { + if (isSync) { + workLoopSync(); + } else { + workLoop(); + } + break; + } catch (thrownValue) { + // Reset module-level state that was set during the render phase. + resetContextDependences(); + resetHooks(); + + var sourceFiber = workInProgress; + if (sourceFiber === null || sourceFiber.return === null) { + // Expected to be working on a non-root fiber. This is a fatal error + // because there's no ancestor that can handle it; the root is + // supposed to capture all errors that weren't caught by an error + // boundary. + prepareFreshStack(root, expirationTime); + workPhase = prevWorkPhase; + throw thrownValue; + } + + if (enableProfilerTimer && sourceFiber.mode & ProfileMode) { + // Record the time spent rendering before an error was thrown. This + // avoids inaccurate Profiler durations in the case of a + // suspended render. + stopProfilerTimerIfRunningAndRecordDelta(sourceFiber, true); + } + + var returnFiber = sourceFiber.return; + throwException( + root, + returnFiber, + sourceFiber, + thrownValue, + renderExpirationTime + ); + workInProgress = completeUnitOfWork(sourceFiber); + } + } while (true); + + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + + if (workInProgress !== null) { + // There's still work left over. Return a continuation. + stopInterruptedWorkLoopTimer(); + if (expirationTime !== Sync) { + startRequestCallbackTimer(); + } + return renderRoot.bind(null, root, expirationTime); + } + } + + // We now have a consistent tree. The next step is either to commit it, or, if + // something suspended, wait to commit it after a timeout. + stopFinishedWorkLoopTimer(); + + var isLocked = resolveLocksOnRoot(root, expirationTime); + if (isLocked) { + // This root has a lock that prevents it from committing. Exit. If we begin + // work on the root again, without any intervening updates, it will finish + // without doing additional work. + return null; + } + + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + + switch (workInProgressRootExitStatus) { + case RootIncomplete: { + (function() { + { + throw ReactError("Should have a work-in-progress."); + } + })(); + } + // Flow knows about invariant, so it compains if I add a break statement, + // but eslint doesn't know about invariant, so it complains if I do. + // eslint-disable-next-line no-fallthrough + case RootErrored: { + // An error was thrown. First check if there is lower priority work + // scheduled on this root. + var lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. Before raising the error, try rendering + // at the lower priority to see if it fixes it. Use a continuation to + // maintain the existing priority and position in the queue. + return renderRoot.bind(null, root, lastPendingTime); + } + if (!isSync) { + // If we're rendering asynchronously, it's possible the error was + // caused by tearing due to a mutation during an event. Try rendering + // one more time without yiedling to events. + prepareFreshStack(root, expirationTime); + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + return null; + } + // If we're already rendering synchronously, commit the root in its + // errored state. + return commitRoot.bind(null, root, expirationTime); + } + case RootSuspended: { + if (!isSync) { + var _lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. It might be unsuspended. Try rendering + // at that level. + return renderRoot.bind(null, root, _lastPendingTime); + } + // If workInProgressRootMostRecentEventTime is Sync, that means we didn't + // track any event times. That can happen if we retried but nothing switched + // from fallback to content. There's no reason to delay doing no work. + if (workInProgressRootMostRecentEventTime !== Sync) { + var msUntilTimeout = computeMsUntilTimeout( + workInProgressRootMostRecentEventTime, + expirationTime + ); + // Don't bother with a very short suspense time. + if (msUntilTimeout > 10) { + // The render is suspended, it hasn't timed out, and there's no lower + // priority work to do. Instead of committing the fallback + // immediately, wait for more data to arrive. + root.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root, expirationTime), + msUntilTimeout + ); + return null; + } + } + } + // The work expired. Commit immediately. + return commitRoot.bind(null, root, expirationTime); + } + case RootCompleted: { + // The work completed. Ready to commit. + return commitRoot.bind(null, root, expirationTime); + } + default: { + (function() { + { + throw ReactError("Unknown root exit status."); + } + })(); + } + } +} + +function markRenderEventTime(expirationTime) { + if (expirationTime < workInProgressRootMostRecentEventTime) { + workInProgressRootMostRecentEventTime = expirationTime; + } +} + +function renderDidSuspend() { + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootSuspended; + } +} + +function renderDidError() { + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) { + workInProgressRootExitStatus = RootErrored; + } +} + +function inferTimeFromExpirationTime(expirationTime) { + // We don't know exactly when the update was scheduled, but we can infer an + // approximate start time from the expiration time. + var earliestExpirationTimeMs = expirationTimeToMs(expirationTime); + return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; +} + +function workLoopSync() { + // Already timed out, so perform work without checking if we need to yield. + while (workInProgress !== null) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function workLoop() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function performUnitOfWork(unitOfWork) { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = unitOfWork.alternate; + + startWorkTimer(unitOfWork); + setCurrentFiber(unitOfWork); + + var next = void 0; + if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoContext) { + startProfilerTimer(unitOfWork); + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + } + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (next === null) { + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(unitOfWork); + } + + ReactCurrentOwner$2.current = null; + return next; +} + +function completeUnitOfWork(unitOfWork) { + // Attempt to complete the current unit of work, then move to the next + // sibling. If there are no more siblings, return to the parent fiber. + workInProgress = unitOfWork; + do { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = workInProgress.alternate; + var returnFiber = workInProgress.return; + + // Check if the work completed or if something threw. + if ((workInProgress.effectTag & Incomplete) === NoEffect) { + setCurrentFiber(workInProgress); + var next = void 0; + if ( + !enableProfilerTimer || + (workInProgress.mode & ProfileMode) === NoContext + ) { + next = completeWork(current$$1, workInProgress, renderExpirationTime); + } else { + startProfilerTimer(workInProgress); + next = completeWork(current$$1, workInProgress, renderExpirationTime); + // Update render duration assuming we didn't error. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + } + stopWorkTimer(workInProgress); + resetCurrentFiber(); + resetChildExpirationTime(workInProgress); + + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + return next; + } + + if ( + returnFiber !== null && + // Do not append effects to parents if a sibling failed to complete + (returnFiber.effectTag & Incomplete) === NoEffect + ) { + // Append all the effects of the subtree and this fiber onto the effect + // list of the parent. The completion order of the children affects the + // side-effect order. + if (returnFiber.firstEffect === null) { + returnFiber.firstEffect = workInProgress.firstEffect; + } + if (workInProgress.lastEffect !== null) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; + } + returnFiber.lastEffect = workInProgress.lastEffect; + } + + // If this fiber had side-effects, we append it AFTER the children's + // side-effects. We can perform certain side-effects earlier if needed, + // by doing multiple passes over the effect list. We don't want to + // schedule our own side-effect on our own list because if end up + // reusing children we'll schedule this effect onto itself since we're + // at the end. + var effectTag = workInProgress.effectTag; + + // Skip both NoWork and PerformedWork tags when creating the effect + // list. PerformedWork effect is read by React DevTools but shouldn't be + // committed. + if (effectTag > PerformedWork) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress; + } else { + returnFiber.firstEffect = workInProgress; + } + returnFiber.lastEffect = workInProgress; + } + } + } else { + // This fiber did not complete because something threw. Pop values off + // the stack without entering the complete phase. If this is a boundary, + // capture values if possible. + var _next = unwindWork(workInProgress, renderExpirationTime); + + // Because this fiber did not complete, don't reset its expiration time. + + if ( + enableProfilerTimer && + (workInProgress.mode & ProfileMode) !== NoContext + ) { + // Record the render duration for the fiber that errored. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + + // Include the time spent working on failed children before continuing. + var actualDuration = workInProgress.actualDuration; + var child = workInProgress.child; + while (child !== null) { + actualDuration += child.actualDuration; + child = child.sibling; + } + workInProgress.actualDuration = actualDuration; + } + + if (_next !== null) { + // If completing this work spawned new work, do that next. We'll come + // back here again. + // Since we're restarting, remove anything that is not a host effect + // from the effect tag. + // TODO: The name stopFailedWorkTimer is misleading because Suspense + // also captures and restarts. + stopFailedWorkTimer(workInProgress); + _next.effectTag &= HostEffectMask; + return _next; + } + stopWorkTimer(workInProgress); + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its effect list. + returnFiber.firstEffect = returnFiber.lastEffect = null; + returnFiber.effectTag |= Incomplete; + } + } + + var siblingFiber = workInProgress.sibling; + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } + // Otherwise, return to the parent + workInProgress = returnFiber; + } while (workInProgress !== null); + + // We've reached the root. + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootCompleted; + } + return null; +} + +function resetChildExpirationTime(completedWork) { + if ( + renderExpirationTime !== Never && + completedWork.childExpirationTime === Never + ) { + // The children of this component are hidden. Don't bubble their + // expiration times. + return; + } + + var newChildExpirationTime = NoWork; + + // Bubble up the earliest expiration time. + if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoContext) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var actualDuration = completedWork.actualDuration; + var treeBaseDuration = completedWork.selfBaseDuration; + + // When a fiber is cloned, its actualDuration is reset to 0. This value will + // only be updated if work is done on the fiber (i.e. it doesn't bailout). + // When work is done, it should bubble to the parent's actualDuration. If + // the fiber has not been cloned though, (meaning no work was done), then + // this value will reflect the amount of time spent working on a previous + // render. In that case it should not bubble. We determine whether it was + // cloned by comparing the child pointer. + var shouldBubbleActualDurations = + completedWork.alternate === null || + completedWork.child !== completedWork.alternate.child; + + var child = completedWork.child; + while (child !== null) { + var childUpdateExpirationTime = child.expirationTime; + var childChildExpirationTime = child.childExpirationTime; + if (childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childUpdateExpirationTime; + } + if (childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childChildExpirationTime; + } + if (shouldBubbleActualDurations) { + actualDuration += child.actualDuration; + } + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; + while (_child !== null) { + var _childUpdateExpirationTime = _child.expirationTime; + var _childChildExpirationTime = _child.childExpirationTime; + if (_childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childUpdateExpirationTime; + } + if (_childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childChildExpirationTime; + } + _child = _child.sibling; + } + } + + completedWork.childExpirationTime = newChildExpirationTime; +} + +function commitRoot(root, expirationTime) { + runWithPriority( + ImmediatePriority, + commitRootImpl.bind(null, root, expirationTime) + ); + // If there are passive effects, schedule a callback to flush them. This goes + // outside commitRootImpl so that it inherits the priority of the render. + if (rootWithPendingPassiveEffects !== null) { + var priorityLevel = getCurrentPriorityLevel(); + scheduleCallback(priorityLevel, function() { + flushPassiveEffects(); + return null; + }); + } + return null; +} + +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + flushRenderPhaseStrictModeWarningsInDEV(); + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + var finishedWork = root.current.alternate; + (function() { + if (!(finishedWork !== null)) { + throw ReactError("Should have a work-in-progress root."); + } + })(); + + // commitRoot never returns a continuation; it always finishes synchronously. + // So we can clear these now to allow a new callback to be scheduled. + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + + startCommitTimer(); + + // Update the first and last pending times on this root. The new first + // pending time is whatever is left on the root fiber. + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; + var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + var firstPendingTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = firstPendingTimeBeforeCommit; + if (firstPendingTimeBeforeCommit < root.lastPendingTime) { + // This usually means we've finished all the work, but it can also happen + // when something gets downprioritized during render, like a hidden tree. + root.lastPendingTime = firstPendingTimeBeforeCommit; + } + + if (root === workInProgressRoot) { + // We can reset these now that they are finished. + workInProgressRoot = null; + workInProgress = null; + renderExpirationTime = NoWork; + } else { + } + // This indicates that the last root we worked on is not the same one that + // we're committing now. This most commonly happens when a suspended root + // times out. + + // Get the list of effects. + var firstEffect = void 0; + if (finishedWork.effectTag > PerformedWork) { + // A fiber's effect list consists only of its children, not itself. So if + // the root has an effect, we need to add it to the end of the list. The + // resulting list is the set that would belong to the root's parent, if it + // had one; that is, all the effects in the tree including the root. + if (finishedWork.lastEffect !== null) { + finishedWork.lastEffect.nextEffect = finishedWork; + firstEffect = finishedWork.firstEffect; + } else { + firstEffect = finishedWork; + } + } else { + // There is no effect on the root. + firstEffect = finishedWork.firstEffect; + } + + if (firstEffect !== null) { + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + // Reset this to null before calling lifecycles + ReactCurrentOwner$2.current = null; + + // The commit phase is broken into several sub-phases. We do a separate pass + // of the effect list for each phase: all mutation effects come before all + // layout effects, and so on. + + // The first phase a "before mutation" phase. We use this phase to read the + // state of the host tree right before we mutate it. This is where + // getSnapshotBeforeUpdate is called. + startCommitSnapshotEffectsTimer(); + prepareForCommit(root.containerInfo); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitBeforeMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitSnapshotEffectsTimer(); + + if (enableProfilerTimer) { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + } + + // The next phase is the mutation phase, where we mutate the host tree. + startCommitHostEffectsTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitHostEffectsTimer(); + resetAfterCommit(root.containerInfo); + + // The work-in-progress tree is now the current tree. This must come after + // the mutation phase, so that the previous tree is still current during + // componentWillUnmount, but before the layout phase, so that the finished + // work is current during componentDidMount/Update. + root.current = finishedWork; + + // The next phase is the layout phase, where we call effects that read + // the host tree after it's been mutated. The idiomatic use case for this is + // layout, but class component lifecycles also fire here for legacy reasons. + startCommitLifeCyclesTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback( + null, + commitLayoutEffects, + null, + root, + expirationTime + ); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error2 = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error2); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitLifeCyclesTimer(); + + nextEffect = null; + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + workPhase = prevWorkPhase; + } else { + // No effects. + root.current = finishedWork; + // Measure these anyway so the flamegraph explicitly shows that there were + // no effects. + // TODO: Maybe there's a better way to report this. + startCommitSnapshotEffectsTimer(); + stopCommitSnapshotEffectsTimer(); + if (enableProfilerTimer) { + recordCommitTime(); + } + startCommitHostEffectsTimer(); + stopCommitHostEffectsTimer(); + startCommitLifeCyclesTimer(); + stopCommitLifeCyclesTimer(); + } + + stopCommitTimer(); + + if (rootDoesHavePassiveEffects) { + // This commit has passive effects. Stash a reference to them. But don't + // schedule a callback until after flushing layout work. + rootDoesHavePassiveEffects = false; + rootWithPendingPassiveEffects = root; + pendingPassiveEffectsExpirationTime = expirationTime; + } else { + if (enableSchedulerTracing) { + // If there are no passive effects, then we can complete the pending + // interactions. Otherwise, we'll wait until after the passive effects + // are flushed. + finishPendingInteractions(root, expirationTime); + } + } + + // Check if there's remaining work on this root + var remainingExpirationTime = root.firstPendingTime; + if (remainingExpirationTime !== NoWork) { + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + remainingExpirationTime + ); + scheduleCallbackForRoot(root, priorityLevel, remainingExpirationTime); + } else { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } + + onCommitRoot(finishedWork.stateNode); + + if (remainingExpirationTime === Sync) { + // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; + } + } else { + nestedUpdateCount = 0; + } + + if (hasUncaughtError) { + hasUncaughtError = false; + var _error3 = firstUncaughtError; + firstUncaughtError = null; + throw _error3; + } + + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. We just committed the initial mount of + // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired + // synchronously, but layout updates should be deferred until the end + // of the batch. + return null; + } + + // If layout work was scheduled, flush it now. + flushImmediateQueue(); + return null; +} + +function commitBeforeMutationEffects() { + while (nextEffect !== null) { + if ((nextEffect.effectTag & Snapshot) !== NoEffect) { + setCurrentFiber(nextEffect); + recordEffect(); + + var current$$1 = nextEffect.alternate; + commitBeforeMutationLifeCycles(current$$1, nextEffect); + + resetCurrentFiber(); + } + nextEffect = nextEffect.nextEffect; + } +} + +function commitMutationEffects() { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & ContentReset) { + commitResetTextContent(nextEffect); + } + + if (effectTag & Ref) { + var current$$1 = nextEffect.alternate; + if (current$$1 !== null) { + commitDetachRef(current$$1); + } + } + + // The following switch statement is only concerned about placement, + // updates, and deletions. To avoid needing to add a case for every possible + // bitmap value, we remove the secondary effects from the effect tag and + // switch on that value. + var primaryEffectTag = effectTag & (Placement | Update | Deletion); + switch (primaryEffectTag) { + case Placement: { + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + // TODO: findDOMNode doesn't rely on this any more but isMounted does + // and isMounted is deprecated anyway so we should be able to kill this. + nextEffect.effectTag &= ~Placement; + break; + } + case PlacementAndUpdate: { + // Placement + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + nextEffect.effectTag &= ~Placement; + + // Update + var _current = nextEffect.alternate; + commitWork(_current, nextEffect); + break; + } + case Update: { + var _current2 = nextEffect.alternate; + commitWork(_current2, nextEffect); + break; + } + case Deletion: { + commitDeletion(nextEffect); + break; + } + } + + // TODO: Only record a mutation effect if primaryEffectTag is non-zero. + recordEffect(); + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function commitLayoutEffects(root, committedExpirationTime) { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & (Update | Callback)) { + recordEffect(); + var current$$1 = nextEffect.alternate; + commitLifeCycles(root, current$$1, nextEffect, committedExpirationTime); + } + + if (effectTag & Ref) { + recordEffect(); + commitAttachRef(nextEffect); + } + + if (effectTag & Passive) { + rootDoesHavePassiveEffects = true; + } + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function flushPassiveEffects() { + if (rootWithPendingPassiveEffects === null) { + return false; + } + var root = rootWithPendingPassiveEffects; + var expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = NoWork; + + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Cannot flush passive effects while already rendering."); + } + })(); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + + // Note: This currently assumes there are no passive effects on the root + // fiber, because the root is not part of its own effect list. This could + // change in the future. + var effect = root.current.firstEffect; + while (effect !== null) { + { + setCurrentFiber(effect); + invokeGuardedCallback(null, commitPassiveHookEffects, null, effect); + if (hasCaughtError()) { + (function() { + if (!(effect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(effect, error); + } + resetCurrentFiber(); + } + effect = effect.nextEffect; + } + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + } + + workPhase = prevWorkPhase; + flushImmediateQueue(); + + // If additional passive effects were scheduled, increment a counter. If this + // exceeds the limit, we'll fire a warning. + nestedPassiveUpdateCount = + rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1; + + return true; +} + +function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); +} + +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} + +function prepareToThrowUncaughtError(error) { + if (!hasUncaughtError) { + hasUncaughtError = true; + firstUncaughtError = error; + } +} +var onUncaughtError = prepareToThrowUncaughtError; + +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber, errorInfo, Sync); + enqueueUpdate(rootFiber, update); + var root = markUpdateTimeFromFiberToRoot(rootFiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } +} + +function captureCommitPhaseError(sourceFiber, error) { + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + return; + } + + var fiber = sourceFiber.return; + while (fiber !== null) { + if (fiber.tag === HostRoot) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + return; + } else if (fiber.tag === ClassComponent) { + var ctor = fiber.type; + var instance = fiber.stateNode; + if ( + typeof ctor.getDerivedStateFromError === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createClassErrorUpdate( + fiber, + errorInfo, + // TODO: This is always sync + Sync + ); + enqueueUpdate(fiber, update); + var root = markUpdateTimeFromFiberToRoot(fiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } + return; + } + } + fiber = fiber.return; + } +} + +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + if (pingCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(thenable); + } + + if (workInProgressRoot === root && renderExpirationTime === suspendedTime) { + // Received a ping at the same priority level at which we're currently + // rendering. Restart from the root. Don't need to schedule a ping because + // we're already working on this tree. + prepareFreshStack(root, renderExpirationTime); + return; + } + + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime < suspendedTime) { + // The root is no longer suspended at this time. + return; + } + + var pingTime = root.pingTime; + if (pingTime !== NoWork && pingTime < suspendedTime) { + // There's already a lower priority ping scheduled. + return; + } + + // Mark the time at which this ping was scheduled. + root.pingTime = suspendedTime; + + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + suspendedTime + ); + scheduleCallbackForRoot(root, priorityLevel, suspendedTime); +} + +function retryTimedOutBoundary(boundaryFiber) { + // The boundary fiber (a Suspense component) previously timed out and was + // rendered in its fallback state. One of the promises that suspended it has + // resolved, which means at least part of the tree was likely unblocked. Try + // rendering again, at a new expiration time. + var currentTime = requestCurrentTime(); + var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); + // TODO: Special case idle priority? + var priorityLevel = inferPriorityFromExpirationTime(currentTime, retryTime); + var root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime); + if (root !== null) { + scheduleCallbackForRoot(root, priorityLevel, retryTime); + } +} + +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = void 0; + if (enableSuspenseServerRenderer) { + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + break; + case DehydratedSuspenseComponent: + retryCache = boundaryFiber.memoizedState; + break; + default: + (function() { + { + throw ReactError( + "Pinged unknown suspense boundary type. This is probably a bug in React." + ); + } + })(); + } + } else { + retryCache = boundaryFiber.stateNode; + } + + if (retryCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(thenable); + } + + retryTimedOutBoundary(boundaryFiber); +} + +// Computes the next Just Noticeable Difference (JND) boundary. +// The theory is that a person can't tell the difference between small differences in time. +// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable +// difference in the experience. However, waiting for longer might mean that we can avoid +// showing an intermediate loading state. The longer we have already waited, the harder it +// is to tell small differences in time. Therefore, the longer we've already waited, +// the longer we can wait additionally. At some point we have to give up though. +// We pick a train model where the next boundary commits at a consistent schedule. +// These particular numbers are vague estimates. We expect to adjust them based on research. +function jnd(timeElapsed) { + return timeElapsed < 120 + ? 120 + : timeElapsed < 480 + ? 480 + : timeElapsed < 1080 + ? 1080 + : timeElapsed < 1920 + ? 1920 + : timeElapsed < 3000 + ? 3000 + : timeElapsed < 4320 + ? 4320 + : ceil(timeElapsed / 1960) * 1960; +} + +function computeMsUntilTimeout(mostRecentEventTime, committedExpirationTime) { + if (disableYielding) { + // Timeout immediately when yielding is disabled. + return 0; + } + + var eventTimeMs = inferTimeFromExpirationTime(mostRecentEventTime); + var currentTimeMs = now(); + var timeElapsed = currentTimeMs - eventTimeMs; + + var msUntilTimeout = jnd(timeElapsed) - timeElapsed; + + // Compute the time until this render pass would expire. + var timeUntilExpirationMs = + expirationTimeToMs(committedExpirationTime) - currentTimeMs; + + // Clamp the timeout to the expiration time. + // TODO: Once the event time is exact instead of inferred from expiration time + // we don't need this. + if (timeUntilExpirationMs < msUntilTimeout) { + msUntilTimeout = timeUntilExpirationMs; + } + + // This is the value that is passed to `setTimeout`. + return msUntilTimeout; +} + +function checkForNestedUpdates() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + rootWithNestedUpdates = null; + (function() { + { + throw ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + ); + } + })(); + } + + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + warning$1( + false, + "Maximum update depth exceeded. This can happen when a component " + + "calls setState inside useEffect, but useEffect either doesn't " + + "have a dependency array, or one of the dependencies changes on " + + "every render." + ); + } + } +} + +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + ReactStrictModeWarnings.flushLegacyContextWarning(); + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.flushPendingDeprecationWarnings(); + } + } +} + +function stopFinishedWorkLoopTimer() { + var didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function stopInterruptedWorkLoopTimer() { + // TODO: Track which fiber caused the interruption. + var didCompleteRoot = false; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function checkForInterruption(fiberThatReceivedUpdate, updateExpirationTime) { + if ( + enableUserTimingAPI && + workInProgressRoot !== null && + updateExpirationTime > renderExpirationTime + ) { + interruptedBy = fiberThatReceivedUpdate; + } +} + +var didWarnStateUpdateForUnmountedComponent = null; +function warnAboutUpdateOnUnmountedFiberInDEV(fiber) { + { + var tag = fiber.tag; + if ( + tag !== HostRoot && + tag !== ClassComponent && + tag !== FunctionComponent && + tag !== ForwardRef && + tag !== MemoComponent && + tag !== SimpleMemoComponent + ) { + // Only warn for user-defined components, not internal ones like Suspense. + return; + } + // We show the whole stack but dedupe on the top component's name because + // the problematic code almost always lies inside that component. + var componentName = getComponentName(fiber.type) || "ReactComponent"; + if (didWarnStateUpdateForUnmountedComponent !== null) { + if (didWarnStateUpdateForUnmountedComponent.has(componentName)) { + return; + } + didWarnStateUpdateForUnmountedComponent.add(componentName); + } else { + didWarnStateUpdateForUnmountedComponent = new Set([componentName]); + } + warningWithoutStack$1( + false, + "Can't perform a React state update on an unmounted component. This " + + "is a no-op, but it indicates a memory leak in your application. To " + + "fix, cancel all subscriptions and asynchronous tasks in %s.%s", + tag === ClassComponent + ? "the componentWillUnmount method" + : "a useEffect cleanup function", + getStackByFiberInDevAndProd(fiber) + ); + } +} + +var beginWork$$1 = void 0; +if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + var dummyFiber = null; + beginWork$$1 = function(current$$1, unitOfWork, expirationTime) { + // If a component throws an error, we replay it again in a synchronously + // dispatched event, so that the debugger will treat it as an uncaught + // error See ReactErrorUtils for more information. + + // Before entering the begin phase, copy the work-in-progress onto a dummy + // fiber. If beginWork throws, we'll use this to reset the state. + var originalWorkInProgressCopy = assignFiberPropertiesInDEV( + dummyFiber, + unitOfWork + ); + try { + return beginWork$1(current$$1, unitOfWork, expirationTime); + } catch (originalError) { + if ( + originalError !== null && + typeof originalError === "object" && + typeof originalError.then === "function" + ) { + // Don't replay promises. Treat everything else like an error. + throw originalError; + } + + // Keep this code in sync with renderRoot; any changes here must have + // corresponding changes there. + resetContextDependences(); + resetHooks(); + + // Unwind the failed stack frame + unwindInterruptedWork(unitOfWork); + + // Restore the original properties of the fiber. + assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); + + if (enableProfilerTimer && unitOfWork.mode & ProfileMode) { + // Reset the profiler timer. + startProfilerTimer(unitOfWork); + } + + // Run beginWork again. + invokeGuardedCallback( + null, + beginWork$1, + null, + current$$1, + unitOfWork, + expirationTime + ); + + if (hasCaughtError()) { + var replayError = clearCaughtError(); + // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`. + // Rethrow this error instead of the original one. + throw replayError; + } else { + // This branch is reachable if the render phase is impure. + throw originalError; + } + } + }; +} else { + beginWork$$1 = beginWork$1; +} + +var didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInGetChildContext = false; +function warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber) { + { + if (fiber.tag === ClassComponent) { + switch (phase) { + case "getChildContext": + if (didWarnAboutUpdateInGetChildContext) { + return; + } + warningWithoutStack$1( + false, + "setState(...): Cannot call setState() inside getChildContext()" + ); + didWarnAboutUpdateInGetChildContext = true; + break; + case "render": + if (didWarnAboutUpdateInRender) { + return; + } + warningWithoutStack$1( + false, + "Cannot update during an existing state transition (such as " + + "within `render`). Render methods should be a pure function of " + + "props and state." + ); + didWarnAboutUpdateInRender = true; + break; + } + } + } +} + +function warnIfNotCurrentlyActingUpdatesInDEV(fiber) { + { + if ( + workPhase === NotWorking && + ReactShouldWarnActingUpdates.current === false + ) { + warningWithoutStack$1( + false, + "An update to %s inside a test was not wrapped in act(...).\n\n" + + "When testing, code that causes React state updates should be " + + "wrapped into act(...):\n\n" + + "act(() => {\n" + + " /* fire events that update state */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://fb.me/react-wrap-tests-with-act" + + "%s", + getComponentName(fiber.type), + getStackByFiberInDevAndProd(fiber) + ); + } + } +} + +var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; + +function computeThreadID(root, expirationTime) { + // Interaction threads are unique per root and expiration time. + return expirationTime * 1000 + root.interactionThreadID; +} + +function schedulePendingInteraction(root, expirationTime) { + // This is called when work is scheduled on a root. It sets up a pending + // interaction, which is completed once the work commits. + if (!enableSchedulerTracing) { + return; + } + + var interactions = tracing.__interactionsRef.current; + if (interactions.size > 0) { + var pendingInteractionMap = root.pendingInteractionMap; + var pendingInteractions = pendingInteractionMap.get(expirationTime); + if (pendingInteractions != null) { + interactions.forEach(function(interaction) { + if (!pendingInteractions.has(interaction)) { + // Update the pending async work count for previously unscheduled interaction. + interaction.__count++; + } + + pendingInteractions.add(interaction); + }); + } else { + pendingInteractionMap.set(expirationTime, new Set(interactions)); + + // Update the pending async work count for the current interactions. + interactions.forEach(function(interaction) { + interaction.__count++; + }); + } + + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + subscriber.onWorkScheduled(interactions, threadID); + } + } +} + +function startWorkOnPendingInteraction(root, expirationTime) { + // This is called when new work is started on a root. + if (!enableSchedulerTracing) { + return; + } + + // Determine which interactions this batch of work currently includes, So that + // we can accurately attribute time spent working on it, And so that cascading + // work triggered during the render phase will be associated with it. + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + if (scheduledExpirationTime >= expirationTime) { + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + } + }); + + // Store the current set of interactions on the FiberRoot for a few reasons: + // We can re-use it in hot functions like renderRoot() without having to + // recalculate it. We will also use it in commitWork() to pass to any Profiler + // onRender() hooks. This also provides DevTools with a way to access it when + // the onCommitRoot() hook is called. + root.memoizedInteractions = interactions; + + if (interactions.size > 0) { + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + try { + subscriber.onWorkStarted(interactions, threadID); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + } +} + +function finishPendingInteractions(root, committedExpirationTime) { + if (!enableSchedulerTracing) { + return; + } + + var earliestRemainingTimeAfterCommit = root.firstPendingTime; + + var subscriber = void 0; + + try { + subscriber = tracing.__subscriberRef.current; + if (subscriber !== null && root.memoizedInteractions.size > 0) { + var threadID = computeThreadID(root, committedExpirationTime); + subscriber.onWorkStopped(root.memoizedInteractions, threadID); + } + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } finally { + // Clear completed interactions from the pending Map. + // Unless the render was suspended or cascading work was scheduled, + // In which case– leave pending interactions until the subsequent render. + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + // Only decrement the pending interaction count if we're done. + // If there's still work at the current priority, + // That indicates that we are waiting for suspense data. + if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { + pendingInteractionMap.delete(scheduledExpirationTime); + + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + + if (subscriber !== null && interaction.__count === 0) { + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + }); + } + }); + } +} + +// This lets us hook into Fiber to debug what it's doing. +// See https://github.com/facebook/react/pull/8033. +// This is not part of the public API, not even for React DevTools. +// You may only inject a debugTool if you work on React Fiber itself. +var ReactFiberInstrumentation = { + debugTool: null +}; + +var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; + +// 0 is PROD, 1 is DEV. +// Might add PROFILE later. + +var didWarnAboutNestedUpdates = void 0; +var didWarnAboutFindNodeInStrictMode = void 0; + +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; +} + +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + + if (fiber.tag === ClassComponent) { + var Component = fiber.type; + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } + } + + return parentContext; +} + +function scheduleRootUpdate(current$$1, element, expirationTime, callback) { + { + if (phase === "render" && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; + warningWithoutStack$1( + false, + "Render methods should be a pure function of props and state; " + + "triggering nested component updates from render is not allowed. " + + "If necessary, trigger nested updates in componentDidUpdate.\n\n" + + "Check the render method of %s.", + getComponentName(current.type) || "Unknown" + ); + } + } + + var update = createUpdate(expirationTime); + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: element }; + + callback = callback === undefined ? null : callback; + if (callback !== null) { + !(typeof callback === "function") + ? warningWithoutStack$1( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(current$$1, update); + scheduleWork(current$$1, expirationTime); + + return expirationTime; +} + +function updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback +) { + // TODO: If this is a nested container, this won't be the root. + var current$$1 = container.current; + + { + if (ReactFiberInstrumentation_1.debugTool) { + if (current$$1.alternate === null) { + ReactFiberInstrumentation_1.debugTool.onMountContainer(container); + } else if (element === null) { + ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container); + } else { + ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container); + } + } + } + + var context = getContextForSubtree(parentComponent); + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } + + return scheduleRootUpdate(current$$1, element, expirationTime, callback); +} + +function findHostInstance(component) { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; +} + +function findHostInstanceWithWarning(component, methodName) { + { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + if (hostFiber.mode & StrictMode) { + var componentName = getComponentName(fiber.type) || "Component"; + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + if (fiber.mode & StrictMode) { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which is inside StrictMode. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } else { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which renders StrictMode children. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } + } + } + return hostFiber.stateNode; + } + return findHostInstance(component); +} + +function createContainer(containerInfo, isConcurrent, hydrate) { + return createFiberRoot(containerInfo, isConcurrent, hydrate); +} + +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current; + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, current$$1); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback + ); +} + +function getPublicRootInstance(container) { + var containerFiber = container.current; + if (!containerFiber.child) { + return null; + } + switch (containerFiber.child.tag) { + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); + default: + return containerFiber.child.stateNode; + } +} + +var shouldSuspendImpl = function(fiber) { + return false; +}; + +function shouldSuspend(fiber) { + return shouldSuspendImpl(fiber); +} + +var overrideHookState = null; +var overrideProps = null; +var scheduleUpdate = null; +var setSuspenseHandler = null; + +{ + var copyWithSetImpl = function(obj, path, idx, value) { + if (idx >= path.length) { + return value; + } + var key = path[idx]; + var updated = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj); + // $FlowFixMe number or string is fine here + updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value); + return updated; + }; + + var copyWithSet = function(obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; + + // Support DevTools editable values for useState and useReducer. + overrideHookState = function(fiber, id, path, value) { + // For now, the "id" of stateful hooks is just the stateful hook index. + // This may change in the future with e.g. nested hooks. + var currentHook = fiber.memoizedState; + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } + if (currentHook !== null) { + flushPassiveEffects(); + + var newState = copyWithSet(currentHook.memoizedState, path, value); + currentHook.memoizedState = newState; + currentHook.baseState = newState; + + // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. + fiber.memoizedProps = Object.assign({}, fiber.memoizedProps); + + scheduleWork(fiber, Sync); + } + }; + + // Support DevTools props for function components, forwardRef, memo, host components, etc. + overrideProps = function(fiber, path, value) { + flushPassiveEffects(); + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } + scheduleWork(fiber, Sync); + }; + + scheduleUpdate = function(fiber) { + flushPassiveEffects(); + scheduleWork(fiber, Sync); + }; + + setSuspenseHandler = function(newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; +} + +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; + + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: overrideHookState, + overrideProps: overrideProps, + setSuspenseHandler: setSuspenseHandler, + scheduleUpdate: scheduleUpdate, + currentDispatcherRef: ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + if (!findFiberByHostInstance) { + // Might not be implemented by the renderer. + return null; + } + return findFiberByHostInstance(instance); + } + }) + ); +} + +// This file intentionally does *not* have the Flow annotation. +// Don't add it. See `./inline-typed.js` for an explanation. + +function createPortal( + children, + containerInfo, + // TODO: figure out the API for cross-renderer implementation. + implementation +) { + var key = + arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + + return { + // This tag allow us to uniquely identify this as a React Portal + $$typeof: REACT_PORTAL_TYPE, + key: key == null ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} + +// TODO: this is special because it gets imported during build. + +var ReactVersion = "16.8.6"; + +// Modules provided by RN: +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { + /** + * `NativeMethodsMixin` provides methods to access the underlying native + * component directly. This can be useful in cases when you want to focus + * a view or measure its on-screen dimensions, for example. + * + * The methods described here are available on most of the default components + * provided by React Native. Note, however, that they are *not* available on + * composite components that aren't directly backed by a native view. This will + * generally include most components that you define in your own app. For more + * information, see [Direct + * Manipulation](docs/direct-manipulation.html). + * + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. + */ + var NativeMethodsMixin = { + /** + * Determines the location on screen, width, and height of the given view and + * returns the values via an async callback. If successful, the callback will + * be called with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * Note that these measurements are not available until after the rendering + * has been completed in native. If you need the measurements as soon as + * possible, consider using the [`onLayout` + * prop](docs/view.html#onlayout) instead. + */ + measure: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Like [`measure()`](#measure), but measures the view relative an ancestor, + * specified as `relativeToNativeNode`. This means that the returned x, y + * are relative to the origin x, y of the ancestor view. + * + * As always, to obtain a native node handle for a component, you can use + * `findNodeHandle(component)`. + */ + measureLayout: function( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }, + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + setNativeProps: function(nativeProps) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }, + + /** + * Requests focus for the given input or view. The exact behavior triggered + * will depend on the platform and type of view. + */ + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + + { + // hide this from Flow since we can't define these properties outside of + // true without actually implementing them (setting them to undefined + // isn't allowed by ReactClass) + var NativeMethodsMixin_DEV = NativeMethodsMixin; + (function() { + if ( + !( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps + ) + ) { + throw ReactError("Do not override existing functions."); + } + })(); + // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, + // Once these lifecycles have been remove from the reconciler. + NativeMethodsMixin_DEV.componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { + throwOnStylesProp(this, newProps); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function( + newProps + ) { + throwOnStylesProp(this, newProps); + }; + + // React may warn about cWM/cWRP/cWU methods being deprecated. + // Add a flag to suppress these warnings for this special case. + // TODO (bvaughn) Remove this flag once the above methods have been removed. + NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; + NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; + } + + return NativeMethodsMixin; +}; + +function _classCallCheck$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +function _possibleConstructorReturn(self, call) { + if (!self) { + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + } + return call && (typeof call === "object" || typeof call === "function") + ? call + : self; +} + +function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) + Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass); +} + +// Modules provided by RN: +var ReactNativeComponent = function(findNodeHandle, findHostInstance) { + /** + * Superclass that provides methods to access the underlying native component. + * This can be useful when you want to focus a view or measure its dimensions. + * + * Methods implemented by this class are available on most default components + * provided by React Native. However, they are *not* available on composite + * components that are not directly backed by a native view. For more + * information, see [Direct Manipulation](docs/direct-manipulation.html). + * + * @abstract + */ + var ReactNativeComponent = (function(_React$Component) { + _inherits(ReactNativeComponent, _React$Component); + + function ReactNativeComponent() { + _classCallCheck$1(this, ReactNativeComponent); + + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) + ); + } + + /** + * Removes focus. This is the opposite of `focus()`. + */ + + /** + * Due to bugs in Flow's handling of React.createClass, some fields already + * declared in the base class need to be redeclared below. + */ + ReactNativeComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + + /** + * Measures the on-screen location and dimensions. If successful, the callback + * will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * These values are not available until after natives rendering completes. If + * you need the measurements as soon as possible, consider using the + * [`onLayout` prop](docs/view.html#onlayout) instead. + */ + + ReactNativeComponent.prototype.measure = function measure(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Measures the on-screen location and dimensions. Even if the React Native + * root view is embedded within another native view, this method will give you + * the absolute coordinates measured from the window. If successful, the + * callback will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * + * These values are not available until after natives rendering completes. + */ + + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Similar to [`measure()`](#measure), but the resulting location will be + * relative to the supplied ancestor's location. + * + * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. + */ + + ReactNativeComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }; + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + + ReactNativeComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than ReactNative.findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions + + return ReactNativeComponent; +}; + +// Module provided by RN: +var emptyObject$1 = {}; +{ + Object.freeze(emptyObject$1); +} + +var getInspectorDataForViewTag = void 0; + +{ + var traverseOwnerTreeUp = function(hierarchy, instance) { + if (instance) { + hierarchy.unshift(instance); + traverseOwnerTreeUp(hierarchy, instance._debugOwner); + } + }; + + var getOwnerHierarchy = function(instance) { + var hierarchy = []; + traverseOwnerTreeUp(hierarchy, instance); + return hierarchy; + }; + + var lastNonHostInstance = function(hierarchy) { + for (var i = hierarchy.length - 1; i > 1; i--) { + var instance = hierarchy[i]; + + if (instance.tag !== HostComponent) { + return instance; + } + } + return hierarchy[0]; + }; + + var getHostProps = function(fiber) { + var host = findCurrentHostFiber(fiber); + if (host) { + return host.memoizedProps || emptyObject$1; + } + return emptyObject$1; + }; + + var getHostNode = function(fiber, findNodeHandle) { + var hostNode = void 0; + // look for children first for the hostNode + // as composite fibers do not have a hostNode + while (fiber) { + if (fiber.stateNode !== null && fiber.tag === HostComponent) { + hostNode = findNodeHandle(fiber.stateNode); + } + if (hostNode) { + return hostNode; + } + fiber = fiber.child; + } + return null; + }; + + var createHierarchy = function(fiberHierarchy) { + return fiberHierarchy.map(function(fiber) { + return { + name: getComponentName(fiber.type), + getInspectorData: function(findNodeHandle) { + return { + measure: function(callback) { + return ReactNativePrivateInterface.UIManager.measure( + getHostNode(fiber, findNodeHandle), + callback + ); + }, + props: getHostProps(fiber), + source: fiber._debugSource + }; + } + }; + }); + }; + + getInspectorDataForViewTag = function(viewTag) { + var closestInstance = getInstanceFromTag(viewTag); + + // Handle case where user clicks outside of ReactNative + if (!closestInstance) { + return { + hierarchy: [], + props: emptyObject$1, + selection: null, + source: null + }; + } + + var fiber = findCurrentFiberUsingSlowPath(closestInstance); + var fiberHierarchy = getOwnerHierarchy(fiber); + var instance = lastNonHostInstance(fiberHierarchy); + var hierarchy = createHierarchy(fiberHierarchy); + var props = getHostProps(instance); + var source = instance._debugSource; + var selection = fiberHierarchy.indexOf(instance); + + return { + hierarchy: hierarchy, + props: props, + selection: selection, + source: source + }; + }; +} + +// Module provided by RN: +function setNativeProps(handle, nativeProps) { + if (handle._nativeTag == null) { + !(handle._nativeTag != null) + ? warningWithoutStack$1( + false, + "setNativeProps was called with a ref that isn't a " + + "native component. Use React.forwardRef to get access to the underlying native component" + ) + : void 0; + return; + } + + { + warnForStyleProps(nativeProps, handle.viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, handle.viewConfig.validAttributes); + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + handle._nativeTag, + handle.viewConfig.uiViewClassName, + updatePayload + ); + } +} + +// TODO: direct imports like some-package/src/* are bad. Fix me. +// Module provided by RN: +var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; + +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing findNodeHandle inside its render(). " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(owner.type) || "A component" + ) + : void 0; + + owner.stateNode._warnedAboutRefsInRender = true; + } + } + if (componentOrHandle == null) { + return null; + } + if (typeof componentOrHandle === "number") { + // Already a node handle + return componentOrHandle; + } + if (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) { + return componentOrHandle.canonical._nativeTag; + } + var hostInstance = void 0; + { + hostInstance = findHostInstanceWithWarning( + componentOrHandle, + "findNodeHandle" + ); + } + + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; +} + +setBatchingImplementation( + batchedUpdates$1, + interactiveUpdates$1, + flushInteractiveUpdates$1 +); + +function computeComponentStackForErrorReporting(reactTag) { + var fiber = getInstanceFromTag(reactTag); + if (!fiber) { + return ""; + } + return getStackByFiberInDevAndProd(fiber); +} + +var roots = new Map(); + +var ReactNativeRenderer = { + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), + + findNodeHandle: findNodeHandle, + + setNativeProps: setNativeProps, + + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + + if (!root) { + // TODO (bvaughn): If we decide to keep the wrapper component, + // We could create a wrapper for containerTag as well to reduce special casing. + root = createContainer(containerTag, false, false); + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + + return getPublicRootInstance(root); + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + if (root) { + // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + } + }, + unmountComponentAtNodeAndRemoveContainer: function(containerTag) { + ReactNativeRenderer.unmountComponentAtNode(containerTag); + + // Call back into native to remove all of the subviews from this container + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); + }, + createPortal: function(children, containerTag) { + var key = + arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + return createPortal(children, containerTag, null, key); + }, + + unstable_batchedUpdates: batchedUpdates, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + // Used as a mixin in many createClass-based components + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance), + computeComponentStackForErrorReporting: computeComponentStackForErrorReporting + } +}; + +injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 1, + version: ReactVersion, + rendererPackageName: "react-native-renderer" +}); + +var ReactNativeRenderer$2 = Object.freeze({ + default: ReactNativeRenderer +}); + +var ReactNativeRenderer$3 = + (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var reactNativeRenderer = + ReactNativeRenderer$3.default || ReactNativeRenderer$3; + +module.exports = reactNativeRenderer; + + })(); +} diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js similarity index 99% rename from Libraries/Renderer/oss/ReactNativeRenderer-dev.js rename to Libraries/Renderer/implementations/ReactNativeRenderer-dev.js index 38166b62db37e4..1566edf036983a 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js @@ -16,19 +16,12 @@ if (__DEV__) { (function() { "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); -var UIManager = require("UIManager"); -var RCTEventEmitter = require("RCTEventEmitter"); +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); var React = require("react"); -var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); -var deepDiffer = require("deepDiffer"); -var flattenStyle = require("flattenStyle"); -var TextInputState = require("TextInputState"); var checkPropTypes = require("prop-types/checkPropTypes"); var Scheduler = require("scheduler"); var tracing = require("scheduler/tracing"); -var ExceptionsManager = require("ExceptionsManager"); // Do not require this module directly! Use a normal error constructor with // template literal strings. The messages will be converted to ReactError during @@ -1561,7 +1554,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get$$1 + get: get }; function set(val) { @@ -1570,7 +1563,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get$$1() { + function get() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1913,7 +1906,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes$1 = { +var eventTypes = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -2204,12 +2197,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : topLevelType === TOP_SELECTION_CHANGE - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -2243,7 +2236,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2254,7 +2247,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -2271,7 +2264,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -2282,7 +2275,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2351,7 +2344,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2401,11 +2394,11 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes$1.responderStart + ? eventTypes.responderStart : isResponderTouchMove - ? eventTypes$1.responderMove + ? eventTypes.responderMove : isResponderTouchEnd - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null; if (incrementalTouch) { @@ -2428,9 +2421,9 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : isResponderRelease - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( @@ -2462,8 +2455,18 @@ var ResponderEventPlugin = { } }; +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + var ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: eventTypes$1, /** * @see {EventPluginHub.extractEvents} @@ -2478,10 +2481,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType]; - var directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; (function() { if (!(bubbleDispatchConfig || directDispatchConfig)) { throw ReactError( @@ -2816,9 +2817,12 @@ var ReactNativeGlobalResponderHandler = { onChange: function(from, to, blockNativeResponder) { if (to !== null) { var tag = to.stateNode._nativeTag; - UIManager.setJSResponder(tag, blockNativeResponder); + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); } else { - UIManager.clearJSResponder(); + ReactNativePrivateInterface.UIManager.clearJSResponder(); } } }; @@ -2827,7 +2831,7 @@ var ReactNativeGlobalResponderHandler = { /** * Register the event emitter with the native bridge */ -RCTEventEmitter.register({ +ReactNativePrivateInterface.RCTEventEmitter.register({ receiveEvent: receiveEvent, receiveTouches: receiveTouches }); @@ -2858,7 +2862,7 @@ ResponderEventPlugin.injection.injectGlobalResponderHandler( * supported we can rename it. */ -function get$1(key) { +function get(key) { return key._reactInternalFiber; } @@ -3125,7 +3129,7 @@ function isMounted(component) { } } - var fiber = get$1(component); + var fiber = get(component); if (!fiber) { return false; } @@ -3344,7 +3348,7 @@ function defaultDiffer(prevProp, nextProp) { return true; } else { // For objects and arrays, the default diffing algorithm is a deep compare - return deepDiffer(prevProp, nextProp); + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); } } @@ -3484,7 +3488,7 @@ function diffNestedProperty( return diffProperties( updatePayload, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. nextProp, validAttributes @@ -3495,7 +3499,7 @@ function diffNestedProperty( updatePayload, prevProp, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -3852,15 +3856,15 @@ var ReactNativeFiberHostComponent = (function() { } ReactNativeFiberHostComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.measure = function measure(callback) { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -3869,7 +3873,7 @@ var ReactNativeFiberHostComponent = (function() { ReactNativeFiberHostComponent.prototype.measureInWindow = function measureInWindow( callback ) { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -3903,7 +3907,7 @@ var ReactNativeFiberHostComponent = (function() { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( this._nativeTag, relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -3933,7 +3937,7 @@ var ReactNativeFiberHostComponent = (function() { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( this._nativeTag, this.viewConfig.uiViewClassName, updatePayload @@ -4008,6 +4012,8 @@ var didNotFindHydratableTextInstance = shim$1; var didNotFindHydratableSuspenseInstance = shim$1; // Modules provided by RN: +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Unused // Unused var UPDATE_SIGNAL = {}; @@ -4051,19 +4057,21 @@ function createInstance( internalInstanceHandle ) { var tag = allocateTag(); - var viewConfig = ReactNativeViewConfigRegistry.get(type); + var viewConfig = getViewConfigForType(type); { for (var key in viewConfig.validAttributes) { if (props.hasOwnProperty(key)) { - deepFreezeAndThrowOnMutationInDev(props[key]); + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); } } } var updatePayload = create(props, viewConfig.validAttributes); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, // reactTag viewConfig.uiViewClassName, // viewName rootContainerInstance, // rootTag @@ -4096,7 +4104,7 @@ function createTextInstance( var tag = allocateTag(); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, // reactTag "RCTRawText", // viewName rootContainerInstance, // rootTag @@ -4128,7 +4136,7 @@ function finalizeInitialChildren( : child._nativeTag; }); - UIManager.setChildren( + ReactNativePrivateInterface.UIManager.setChildren( parentInstance._nativeTag, // containerTag nativeTags // reactTags ); @@ -4224,7 +4232,7 @@ function appendChild(parentInstance, child) { children.splice(index, 1); children.push(child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerTag [index], // moveFromIndices [children.length - 1], // moveToIndices @@ -4235,7 +4243,7 @@ function appendChild(parentInstance, child) { } else { children.push(child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerTag [], // moveFromIndices [], // moveToIndices @@ -4248,14 +4256,14 @@ function appendChild(parentInstance, child) { function appendChildToContainer(parentInstance, child) { var childTag = typeof child === "number" ? child : child._nativeTag; - UIManager.setChildren( + ReactNativePrivateInterface.UIManager.setChildren( parentInstance, // containerTag [childTag] // reactTags ); } function commitTextUpdate(textInstance, oldText, newText) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( textInstance, // reactTag "RCTRawText", // viewName { text: newText } // props @@ -4280,7 +4288,7 @@ function commitUpdate( // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, // reactTag viewConfig.uiViewClassName, // viewName updatePayload // props @@ -4298,7 +4306,7 @@ function insertBefore(parentInstance, child, beforeChild) { var beforeChildIndex = children.indexOf(beforeChild); children.splice(beforeChildIndex, 0, child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerID [index], // moveFromIndices [beforeChildIndex], // moveToIndices @@ -4312,7 +4320,7 @@ function insertBefore(parentInstance, child, beforeChild) { var childTag = typeof child === "number" ? child : child._nativeTag; - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerID [], // moveFromIndices [], // moveToIndices @@ -4342,7 +4350,7 @@ function removeChild(parentInstance, child) { children.splice(index, 1); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerID [], // moveFromIndices [], // moveToIndices @@ -4354,7 +4362,7 @@ function removeChild(parentInstance, child) { function removeChildFromContainer(parentInstance, child) { recursivelyUncacheFiberNode(child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance, // containerID [], // moveFromIndices [], // moveToIndices @@ -4374,7 +4382,7 @@ function hideInstance(instance) { { style: { display: "none" } }, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4392,7 +4400,7 @@ function unhideInstance(instance, props) { props, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -7894,7 +7902,7 @@ function applyDerivedStateFromProps( var classComponentUpdater = { isMounted: isMounted, enqueueSetState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7912,7 +7920,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7932,7 +7940,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(inst, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -15226,7 +15234,10 @@ function showErrorDialog(capturedError) { errorToHandle = new Error("Unspecified error at:" + componentStack); } - ExceptionsManager.handleException(errorToHandle, false); + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); // Return false here to prevent ReactFiberErrorLogger default behavior of // logging error details to console.error. Calls to console.error are @@ -18887,7 +18898,7 @@ function getContextForSubtree(parentComponent) { return emptyContextObject; } - var fiber = get$1(parentComponent); + var fiber = get(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); if (fiber.tag === ClassComponent) { @@ -18973,7 +18984,7 @@ function updateContainerAtExpirationTime( } function findHostInstance(component) { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -19001,7 +19012,7 @@ function findHostInstance(component) { function findHostInstanceWithWarning(component, methodName) { { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -19286,7 +19297,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19334,7 +19345,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19397,7 +19408,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19469,7 +19480,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19482,14 +19493,18 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { * will depend on the platform and type of view. */ focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, /** * Removes focus from an input or view. This is the opposite of `focus()`. */ blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; @@ -19609,7 +19624,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * declared in the base class need to be redeclared below. */ ReactNativeComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; /** @@ -19617,7 +19634,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { */ ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; /** @@ -19662,7 +19681,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19711,7 +19730,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19773,7 +19792,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19844,7 +19863,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19924,7 +19943,7 @@ var getInspectorDataForViewTag = void 0; getInspectorData: function(findNodeHandle) { return { measure: function(callback) { - return UIManager.measure( + return ReactNativePrivateInterface.UIManager.measure( getHostNode(fiber, findNodeHandle), callback ); @@ -19989,7 +20008,7 @@ function setNativeProps(handle, nativeProps) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( handle._nativeTag, handle.viewConfig.uiViewClassName, updatePayload @@ -20100,7 +20119,7 @@ var ReactNativeRenderer = { ReactNativeRenderer.unmountComponentAtNode(containerTag); // Call back into native to remove all of the subviews from this container - UIManager.removeRootView(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); }, createPortal: function(children, containerTag) { var key = diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js new file mode 100644 index 00000000000000..a97536ba85c30c --- /dev/null +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -0,0 +1,7205 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +var instanceCache = {}, + instanceProps = {}; +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +var EMPTY_NATIVE_EVENT = {}; +function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { + var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT, + inst = getInstanceFromTag(rootNodeID); + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + inst, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +ReactNativePrivateInterface.RCTEventEmitter.register({ + receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { + _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); + }, + receiveTouches: function(eventTopLevelType, touches, changedIndices) { + if ( + "topTouchEnd" === eventTopLevelType || + "topTouchCancel" === eventTopLevelType + ) { + var JSCompiler_temp = []; + for (var i = 0; i < changedIndices.length; i++) { + var index = changedIndices[i]; + JSCompiler_temp.push(touches[index]); + touches[index] = null; + } + for (i = changedIndices = 0; i < touches.length; i++) + (index = touches[i]), + null !== index && (touches[changedIndices++] = index); + touches.length = changedIndices; + } else + for (JSCompiler_temp = [], i = 0; i < changedIndices.length; i++) + JSCompiler_temp.push(touches[changedIndices[i]]); + for ( + changedIndices = 0; + changedIndices < JSCompiler_temp.length; + changedIndices++ + ) { + i = JSCompiler_temp[changedIndices]; + i.changedTouches = JSCompiler_temp; + i.touches = touches; + index = null; + var target = i.target; + null === target || void 0 === target || 1 > target || (index = target); + _receiveRootNodeIDEvent(index, eventTopLevelType, i); + } + } +}); +getFiberCurrentPropsFromNode = function(stateNode) { + return instanceProps[stateNode._nativeTag] || null; +}; +getInstanceFromNode = getInstanceFromTag; +getNodeFromInstance = function(inst) { + var tag = inst.stateNode._nativeTag; + void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); + if (!tag) throw ReactError("All native instances should have a tag."); + return tag; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var ReactNativeFiberHostComponent = (function() { + function ReactNativeFiberHostComponent(tag, viewConfig) { + if (!(this instanceof ReactNativeFiberHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; + } + ReactNativeFiberHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.measure = function(callback) { + ReactNativePrivateInterface.UIManager.measure( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { + ReactNativePrivateInterface.UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var relativeNode = void 0; + "number" === typeof relativeToNativeNode + ? (relativeNode = relativeToNativeNode) + : relativeToNativeNode._nativeTag + ? (relativeNode = relativeToNativeNode._nativeTag) + : relativeToNativeNode.canonical && + relativeToNativeNode.canonical._nativeTag && + (relativeNode = relativeToNativeNode.canonical._nativeTag); + null != relativeNode && + ReactNativePrivateInterface.UIManager.measureLayout( + this._nativeTag, + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactNativeFiberHostComponent.prototype.setNativeProps = function( + nativeProps + ) { + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + this.viewConfig.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + nativeProps + ); + }; + return ReactNativeFiberHostComponent; +})(); +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, + nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + 1 === tag % 10 && (tag += 2); + nextReactTag = tag + 2; + return tag; +} +function recursivelyUncacheFiberNode(node) { + if ("number" === typeof node) + delete instanceCache[node], delete instanceProps[node]; + else { + var tag = node._nativeTag; + delete instanceCache[tag]; + delete instanceProps[tag]; + node._children.forEach(recursivelyUncacheFiberNode); + } +} +function finalizeInitialChildren(parentInstance) { + if (0 === parentInstance._children.length) return !1; + var nativeTags = parentInstance._children.map(function(child) { + return "number" === typeof child ? child : child._nativeTag; + }); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); + return !1; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout, + BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority, + fakeCallbackNode = {}, + shouldYield = Scheduler.unstable_shouldYield, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue, providerFiber); + context._currentValue = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = + didCaptureError && "function" !== typeof Component.getDerivedStateFromError + ? null + : shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + mode = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = mode; + renderExpirationTime = current$$1; + renderExpirationTime.return = mode.return = workInProgress; + } else + renderExpirationTime = mode = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else + null !== current$$1.memoizedState + ? ((mode = current$$1.child), + (nextFallbackChildren = mode.sibling), + nextDidTimeout + ? ((renderExpirationTime = nextProps.fallback), + (nextProps = createWorkInProgress(mode, mode.pendingProps, 0)), + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== mode.child && + (nextProps.child = nextDidTimeout)), + (mode = nextProps.sibling = createWorkInProgress( + nextFallbackChildren, + renderExpirationTime, + nextFallbackChildren.expirationTime + )), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + mode.child, + nextProps.children, + renderExpirationTime + ))) + : ((nextFallbackChildren = current$$1.child), + nextDidTimeout + ? ((nextDidTimeout = nextProps.fallback), + (nextProps = createFiberFromFragment(null, mode, 0, null)), + (nextProps.child = nextFallbackChildren), + 0 === (workInProgress.mode & 1) && + (nextProps.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + (mode = nextProps.sibling = createFiberFromFragment( + nextDidTimeout, + mode, + renderExpirationTime, + null + )), + (mode.effectTag |= 2), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren, + nextProps.children, + renderExpirationTime + ))), + (workInProgress.stateNode = current$$1.stateNode); + workInProgress.memoizedState = nextState; + workInProgress.child = renderExpirationTime; + return mode; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function(parent, workInProgress) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag || 6 === node.tag) parent._children.push(node.stateNode); + else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +updateHostContainer = function() {}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + current.memoizedProps !== newProps && + (requiredContext(contextStackCursor$1.current), + (workInProgress.updateQueue = UPDATE_SIGNAL)) && + (workInProgress.effectTag |= 4); +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && (workInProgress.effectTag |= 4); +}; +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function hideOrUnhideAllChildren(finishedWork, isHidden) { + for (var node = finishedWork; ; ) { + if (5 === node.tag) { + var instance = node.stateNode; + if (isHidden) { + var viewConfig = instance.viewConfig; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } else { + instance = node.stateNode; + updatePayload = node.memoizedProps; + viewConfig = instance.viewConfig; + var prevProps = Object.assign({}, updatePayload, { + style: [updatePayload.style, { display: "none" }] + }); + updatePayload = diffProperties( + null, + prevProps, + updatePayload, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + } else { + if (6 === node.tag) throw Error("Not yet implemented."); + if (13 === node.tag && null !== node.memoizedState) { + instance = node.child.sibling; + instance.return = node; + node = instance; + continue; + } else if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitUnmount(current$$1$jscomp$0) { + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(current$$1$jscomp$0); + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = current$$1$jscomp$0.updateQueue; + if ( + null !== updateQueue && + ((updateQueue = updateQueue.lastEffect), null !== updateQueue) + ) { + var effect = (updateQueue = updateQueue.next); + do { + var destroy = effect.destroy; + if (void 0 !== destroy) { + var current$$1 = current$$1$jscomp$0; + try { + destroy(); + } catch (error) { + captureCommitPhaseError(current$$1, error); + } + } + effect = effect.next; + } while (effect !== updateQueue); + } + break; + case 1: + safelyDetachRef(current$$1$jscomp$0); + updateQueue = current$$1$jscomp$0.stateNode; + if ("function" === typeof updateQueue.componentWillUnmount) + try { + (updateQueue.props = current$$1$jscomp$0.memoizedProps), + (updateQueue.state = current$$1$jscomp$0.memoizedState), + updateQueue.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(current$$1$jscomp$0, unmountError); + } + break; + case 5: + safelyDetachRef(current$$1$jscomp$0); + break; + case 4: + unmountHostComponents(current$$1$jscomp$0); + } +} +function isHostParent(fiber) { + return 5 === fiber.tag || 3 === fiber.tag || 4 === fiber.tag; +} +function commitPlacement(finishedWork) { + a: { + for (var parent = finishedWork.return; null !== parent; ) { + if (isHostParent(parent)) { + var parentFiber = parent; + break a; + } + parent = parent.return; + } + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + switch (parentFiber.tag) { + case 5: + parent = parentFiber.stateNode; + var isContainer = !1; + break; + case 3: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + case 4: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + default: + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + parentFiber.effectTag & 16 && (parentFiber.effectTag &= -17); + a: b: for (parentFiber = finishedWork; ; ) { + for (; null === parentFiber.sibling; ) { + if (null === parentFiber.return || isHostParent(parentFiber.return)) { + parentFiber = null; + break a; + } + parentFiber = parentFiber.return; + } + parentFiber.sibling.return = parentFiber.return; + for ( + parentFiber = parentFiber.sibling; + 5 !== parentFiber.tag && 6 !== parentFiber.tag && 18 !== parentFiber.tag; + + ) { + if (parentFiber.effectTag & 2) continue b; + if (null === parentFiber.child || 4 === parentFiber.tag) continue b; + else + (parentFiber.child.return = parentFiber), + (parentFiber = parentFiber.child); + } + if (!(parentFiber.effectTag & 2)) { + parentFiber = parentFiber.stateNode; + break a; + } + } + for (var node = finishedWork; ; ) { + if (5 === node.tag || 6 === node.tag) { + var stateNode = node.stateNode; + if (parentFiber) + if (isContainer) { + if ("number" === typeof parent) + throw ReactError( + "Container does not support insertBefore operation" + ); + } else { + var parentInstance = parent, + beforeChild = parentFiber, + children = parentInstance._children, + index = children.indexOf(stateNode); + 0 <= index + ? (children.splice(index, 1), + (beforeChild = children.indexOf(beforeChild)), + children.splice(beforeChild, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [index], + [beforeChild], + [], + [], + [] + )) + : ((index = children.indexOf(beforeChild)), + children.splice(index, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [ + "number" === typeof stateNode + ? stateNode + : stateNode._nativeTag + ], + [index], + [] + )); + } + else + isContainer + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ + "number" === typeof stateNode ? stateNode : stateNode._nativeTag + ]) + : ((parentInstance = parent), + (children = + "number" === typeof stateNode ? stateNode : stateNode._nativeTag), + (index = parentInstance._children), + (beforeChild = index.indexOf(stateNode)), + 0 <= beforeChild + ? (index.splice(beforeChild, 1), + index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [beforeChild], + [index.length - 1], + [], + [], + [] + )) + : (index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [children], + [index.length - 1], + [] + ))); + } else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function unmountHostComponents(current$$1) { + for ( + var node = current$$1, + currentParentIsValid = !1, + currentParent = void 0, + currentParentIsContainer = void 0; + ; + + ) { + if (!currentParentIsValid) { + currentParentIsValid = node.return; + a: for (;;) { + if (null === currentParentIsValid) + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + switch (currentParentIsValid.tag) { + case 5: + currentParent = currentParentIsValid.stateNode; + currentParentIsContainer = !1; + break a; + case 3: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + case 4: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + } + currentParentIsValid = currentParentIsValid.return; + } + currentParentIsValid = !0; + } + if (5 === node.tag || 6 === node.tag) { + a: for (var root = node, node$jscomp$0 = root; ; ) + if ( + (commitUnmount(node$jscomp$0), + null !== node$jscomp$0.child && 4 !== node$jscomp$0.tag) + ) + (node$jscomp$0.child.return = node$jscomp$0), + (node$jscomp$0 = node$jscomp$0.child); + else { + if (node$jscomp$0 === root) break; + for (; null === node$jscomp$0.sibling; ) { + if (null === node$jscomp$0.return || node$jscomp$0.return === root) + break a; + node$jscomp$0 = node$jscomp$0.return; + } + node$jscomp$0.sibling.return = node$jscomp$0.return; + node$jscomp$0 = node$jscomp$0.sibling; + } + if (currentParentIsContainer) + (root = currentParent), + recursivelyUncacheFiberNode(node.stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); + else { + root = currentParent; + var child = node.stateNode; + recursivelyUncacheFiberNode(child); + node$jscomp$0 = root._children; + child = node$jscomp$0.indexOf(child); + node$jscomp$0.splice(child, 1); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); + } + } else if (4 === node.tag) { + if (null !== node.child) { + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = !0; + node.child.return = node; + node = node.child; + continue; + } + } else if ((commitUnmount(node), null !== node.child)) { + node.child.return = node; + node = node.child; + continue; + } + if (node === current$$1) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === current$$1) return; + node = node.return; + 4 === node.tag && (currentParentIsValid = !1); + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + break; + case 1: + break; + case 5: + var instance = finishedWork.stateNode; + if (null != instance) { + var newProps = finishedWork.memoizedProps; + current$$1 = null !== current$$1 ? current$$1.memoizedProps : newProps; + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + null !== updatePayload && + ((finishedWork = instance.viewConfig), + (instanceProps[instance._nativeTag] = newProps), + (newProps = diffProperties( + null, + current$$1, + newProps, + finishedWork.validAttributes + )), + null != newProps && + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + finishedWork.uiViewClassName, + newProps + )); + } + break; + case 6: + if (null === finishedWork.stateNode) + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); + break; + case 20: + break; + case 3: + break; + case 12: + break; + case 13: + commitSuspenseComponent(finishedWork); + break; + case 17: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState, + newDidTimeout = void 0, + primaryChildParent = finishedWork; + null === newState + ? (newDidTimeout = !1) + : ((newDidTimeout = !0), + (primaryChildParent = finishedWork.child), + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500)); + null !== primaryChildParent && + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + (retryCache.add(thenable), thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + (root$jscomp$0 === workInProgressRoot && + expirationTime === renderExpirationTime) || + prepareFreshStack(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var next = beginWork$$1( + unitOfWork.alternate, + unitOfWork, + renderExpirationTime + ); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === next && (next = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return next; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + a: { + var current = current$$1; + current$$1 = workInProgress; + var renderExpirationTime$jscomp$0 = renderExpirationTime, + newProps = current$$1.pendingProps; + switch (current$$1.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 3: + popHostContainer(current$$1); + popTopLevelContextObject(current$$1); + newProps = current$$1.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + current$$1.effectTag &= -3; + updateHostContainer(current$$1); + break; + case 5: + popHostContext(current$$1); + renderExpirationTime$jscomp$0 = requiredContext( + rootInstanceStackCursor.current + ); + var type = current$$1.type; + if (null !== current && null != current$$1.stateNode) + updateHostComponent$1( + current, + current$$1, + type, + newProps, + renderExpirationTime$jscomp$0 + ), + current.ref !== current$$1.ref && (current$$1.effectTag |= 128); + else if (newProps) { + current = requiredContext(contextStackCursor$1.current); + var type$jscomp$0 = type; + var instance = newProps; + var rootContainerInstance = renderExpirationTime$jscomp$0, + internalInstanceHandle = current$$1, + tag = allocateTag(); + type$jscomp$0 = getViewConfigForType(type$jscomp$0); + var updatePayload = diffProperties( + null, + emptyObject, + instance, + type$jscomp$0.validAttributes + ); + ReactNativePrivateInterface.UIManager.createView( + tag, + type$jscomp$0.uiViewClassName, + rootContainerInstance, + updatePayload + ); + rootContainerInstance = new ReactNativeFiberHostComponent( + tag, + type$jscomp$0 + ); + instanceCache[tag] = internalInstanceHandle; + instanceProps[tag] = instance; + instance = rootContainerInstance; + appendAllChildren(instance, current$$1, !1, !1); + finalizeInitialChildren( + instance, + type, + newProps, + renderExpirationTime$jscomp$0, + current + ) && (current$$1.effectTag |= 4); + current$$1.stateNode = instance; + null !== current$$1.ref && (current$$1.effectTag |= 128); + } else if (null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != current$$1.stateNode) + updateHostText$1( + current, + current$$1, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + type = requiredContext(contextStackCursor$1.current); + renderExpirationTime$jscomp$0 = current$$1; + if (!type.isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + type = allocateTag(); + ReactNativePrivateInterface.UIManager.createView( + type, + "RCTRawText", + current, + { text: newProps } + ); + instanceCache[type] = current$$1; + renderExpirationTime$jscomp$0.stateNode = type; + } + break; + case 11: + break; + case 13: + newProps = current$$1.memoizedState; + if (0 !== (current$$1.effectTag & 64)) { + current$$1.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + newProps = null !== newProps; + renderExpirationTime$jscomp$0 = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime$jscomp$0 = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (type = current.child.sibling), + null !== type && + ((current = current$$1.firstEffect), + null !== current + ? ((current$$1.firstEffect = type), + (type.nextEffect = current)) + : ((current$$1.firstEffect = current$$1.lastEffect = type), + (type.nextEffect = null)), + (type.effectTag = 8)))); + newProps && + !renderExpirationTime$jscomp$0 && + 0 !== (current$$1.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + if (newProps || renderExpirationTime$jscomp$0) + current$$1.effectTag |= 4; + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(current$$1); + updateHostContainer(current$$1); + break; + case 10: + popProvider(current$$1); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + current$$1 = null; + } + newProps = workInProgress; + if (1 === renderExpirationTime || 1 !== newProps.childExpirationTime) { + renderExpirationTime$jscomp$0 = 0; + for (type = newProps.child; null !== type; ) + (current = type.expirationTime), + (instance = type.childExpirationTime), + current > renderExpirationTime$jscomp$0 && + (renderExpirationTime$jscomp$0 = current), + instance > renderExpirationTime$jscomp$0 && + (renderExpirationTime$jscomp$0 = instance), + (type = type.sibling); + newProps.childExpirationTime = renderExpirationTime$jscomp$0; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + 1 < finishedWork.effectTag + ? null !== finishedWork.lastEffect + ? ((finishedWork.lastEffect.nextEffect = finishedWork), + (childExpirationTimeBeforeCommit = finishedWork.firstEffect)) + : (childExpirationTimeBeforeCommit = finishedWork) + : (childExpirationTimeBeforeCommit = finishedWork.firstEffect); + if (null !== childExpirationTimeBeforeCommit) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + ReactCurrentOwner$2.current = null; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + break; + case 6: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + unmountHostComponents(current$$1); + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (effectTag = expirationTime; null !== nextEffect; ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + var current$$1$jscomp$1 = nextEffect.alternate; + current$$1$jscomp$0 = nextEffect; + currentRef = effectTag; + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountLayout, + MountLayout, + current$$1$jscomp$0 + ); + break; + case 1: + var instance$jscomp$0 = current$$1$jscomp$0.stateNode; + if (current$$1$jscomp$0.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$0.componentDidMount(); + else { + var prevProps$jscomp$0 = + current$$1$jscomp$0.elementType === + current$$1$jscomp$0.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + current$$1$jscomp$0.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$0.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$0.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue = current$$1$jscomp$0.updateQueue; + null !== updateQueue && + commitUpdateQueue( + current$$1$jscomp$0, + updateQueue, + instance$jscomp$0, + currentRef + ); + break; + case 3: + var _updateQueue = current$$1$jscomp$0.updateQueue; + if (null !== _updateQueue) { + alternate = null; + if (null !== current$$1$jscomp$0.child) + switch (current$$1$jscomp$0.child.tag) { + case 5: + alternate = current$$1$jscomp$0.child.stateNode; + break; + case 1: + alternate = current$$1$jscomp$0.child.stateNode; + } + commitUpdateQueue( + current$$1$jscomp$0, + _updateQueue, + alternate, + currentRef + ); + } + break; + case 5: + break; + case 6: + break; + case 4: + break; + case 12: + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$1 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$1; + break; + default: + instanceToUse = instance$jscomp$1; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + workPhase = updateExpirationTimeBeforeCommit; + } else root.current = finishedWork; + rootDoesHavePassiveEffects && + ((rootDoesHavePassiveEffects = !1), (rootWithPendingPassiveEffects = root)); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects; + rootWithPendingPassiveEffects = null; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (root = root.current.firstEffect; null !== root; ) { + try { + var finishedWork = root; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === root) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(root, error); + } + root = root.nextEffect; + } + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactNativeRenderer = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function(handle, nativeProps) { + null != handle._nativeTag && + ((nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + handle.viewConfig.validAttributes + )), + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + handle._nativeTag, + handle.viewConfig.uiViewClassName, + nativeProps + )); + }, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = createFiber(3, null, null, 0); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + unmountComponentAtNodeAndRemoveContainer: function(containerTag) { + ReactNativeRenderer.unmountComponentAtNode(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + unstable_batchedUpdates: batchedUpdates, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance), + computeComponentStackForErrorReporting: function(reactTag) { + return (reactTag = getInstanceFromTag(reactTag)) + ? getStackByFiberInDevAndProd(reactTag) + : ""; + } + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactNativeRenderer$2 = { default: ReactNativeRenderer }, + ReactNativeRenderer$3 = + (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; +module.exports = ReactNativeRenderer$3.default || ReactNativeRenderer$3; diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js similarity index 97% rename from Libraries/Renderer/oss/ReactNativeRenderer-prod.js rename to Libraries/Renderer/implementations/ReactNativeRenderer-prod.js index 5fbb834c706292..4e2b964402e434 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js @@ -11,16 +11,10 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), - RCTEventEmitter = require("RCTEventEmitter"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), Scheduler = require("scheduler"); -var ExceptionsManager = require("ExceptionsManager"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -617,7 +611,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -680,7 +674,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -709,12 +703,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -800,7 +794,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -810,7 +804,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -822,7 +816,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -836,7 +830,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -866,11 +860,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -924,9 +918,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -948,8 +942,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -957,10 +958,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1060,7 +1059,7 @@ function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { } }); } -RCTEventEmitter.register({ +ReactNativePrivateInterface.RCTEventEmitter.register({ receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); }, @@ -1110,8 +1109,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) - : UIManager.clearJSResponder(); + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1375,14 +1377,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1450,7 +1452,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1462,7 +1464,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1527,19 +1529,19 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig = viewConfig; } ReactNativeFiberHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.measure = function(callback) { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1558,7 +1560,7 @@ var ReactNativeFiberHostComponent = (function() { relativeToNativeNode.canonical._nativeTag && (relativeNode = relativeToNativeNode.canonical._nativeTag); null != relativeNode && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( this._nativeTag, relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1575,7 +1577,7 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( this._nativeTag, this.viewConfig.uiViewClassName, nativeProps @@ -1588,7 +1590,9 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var UPDATE_SIGNAL = {}, +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, nextReactTag = 3; function allocateTag() { var tag = nextReactTag; @@ -1611,7 +1615,10 @@ function finalizeInitialChildren(parentInstance) { var nativeTags = parentInstance._children.map(function(child) { return "number" === typeof child ? child : child._nativeTag; }); - UIManager.setChildren(parentInstance._nativeTag, nativeTags); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); return !1; } var scheduleTimeout = setTimeout, @@ -4535,7 +4542,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -4607,7 +4614,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { { style: { display: "none" } }, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4625,7 +4632,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { updatePayload, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4778,7 +4785,7 @@ function commitPlacement(finishedWork) { ? (children.splice(index, 1), (beforeChild = children.indexOf(beforeChild)), children.splice(beforeChild, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [index], [beforeChild], @@ -4788,7 +4795,7 @@ function commitPlacement(finishedWork) { )) : ((index = children.indexOf(beforeChild)), children.splice(index, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -4803,7 +4810,7 @@ function commitPlacement(finishedWork) { } else isContainer - ? UIManager.setChildren(parent, [ + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ "number" === typeof stateNode ? stateNode : stateNode._nativeTag ]) : ((parentInstance = parent), @@ -4814,7 +4821,7 @@ function commitPlacement(finishedWork) { 0 <= beforeChild ? (index.splice(beforeChild, 1), index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [beforeChild], [index.length - 1], @@ -4823,7 +4830,7 @@ function commitPlacement(finishedWork) { [] )) : (index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -4900,7 +4907,14 @@ function unmountHostComponents(current$$1) { if (currentParentIsContainer) (root = currentParent), recursivelyUncacheFiberNode(node.stateNode), - UIManager.manageChildren(root, [], [], [], [], [0]); + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); else { root = currentParent; var child = node.stateNode; @@ -4908,7 +4922,14 @@ function unmountHostComponents(current$$1) { node$jscomp$0 = root._children; child = node$jscomp$0.indexOf(child); node$jscomp$0.splice(child, 1); - UIManager.manageChildren(root._nativeTag, [], [], [], [], [child]); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); } } else if (4 === node.tag) { if (null !== node.child) { @@ -4960,7 +4981,7 @@ function commitWork(current$$1, finishedWork) { finishedWork.validAttributes )), null != newProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, finishedWork.uiViewClassName, newProps @@ -4972,9 +4993,11 @@ function commitWork(current$$1, finishedWork) { throw ReactError( "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - UIManager.updateView(finishedWork.stateNode, "RCTRawText", { - text: finishedWork.memoizedProps - }); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); break; case 20: break; @@ -5643,14 +5666,14 @@ function completeUnitOfWork(unitOfWork) { var rootContainerInstance = renderExpirationTime$jscomp$0, internalInstanceHandle = current$$1, tag = allocateTag(); - type$jscomp$0 = ReactNativeViewConfigRegistry.get(type$jscomp$0); + type$jscomp$0 = getViewConfigForType(type$jscomp$0); var updatePayload = diffProperties( null, emptyObject, instance, type$jscomp$0.validAttributes ); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, type$jscomp$0.uiViewClassName, rootContainerInstance, @@ -5699,9 +5722,12 @@ function completeUnitOfWork(unitOfWork) { "Text strings must be rendered within a component." ); type = allocateTag(); - UIManager.createView(type, "RCTRawText", current, { - text: newProps - }); + ReactNativePrivateInterface.UIManager.createView( + type, + "RCTRawText", + current, + { text: newProps } + ); instanceCache[type] = current$$1; renderExpirationTime$jscomp$0.stateNode = type; } @@ -6899,10 +6925,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -6915,7 +6945,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6931,7 +6961,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6953,7 +6983,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -6977,7 +7007,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -6997,7 +7027,7 @@ var roots = new Map(), handle.viewConfig.validAttributes )), null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( handle._nativeTag, handle.viewConfig.uiViewClassName, nativeProps @@ -7033,7 +7063,7 @@ var roots = new Map(), }, unmountComponentAtNodeAndRemoveContainer: function(containerTag) { ReactNativeRenderer.unmountComponentAtNode(containerTag); - UIManager.removeRootView(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); }, createPortal: function(children, containerTag) { return createPortal( @@ -7058,7 +7088,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7074,7 +7104,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7092,7 +7122,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7116,7 +7146,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7124,10 +7154,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance), diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js new file mode 100644 index 00000000000000..656ffb77a84847 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -0,0 +1,7445 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"), + tracing = require("scheduler/tracing"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +var instanceCache = {}, + instanceProps = {}; +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +var EMPTY_NATIVE_EVENT = {}; +function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { + var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT, + inst = getInstanceFromTag(rootNodeID); + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + inst, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +ReactNativePrivateInterface.RCTEventEmitter.register({ + receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { + _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); + }, + receiveTouches: function(eventTopLevelType, touches, changedIndices) { + if ( + "topTouchEnd" === eventTopLevelType || + "topTouchCancel" === eventTopLevelType + ) { + var JSCompiler_temp = []; + for (var i = 0; i < changedIndices.length; i++) { + var index = changedIndices[i]; + JSCompiler_temp.push(touches[index]); + touches[index] = null; + } + for (i = changedIndices = 0; i < touches.length; i++) + (index = touches[i]), + null !== index && (touches[changedIndices++] = index); + touches.length = changedIndices; + } else + for (JSCompiler_temp = [], i = 0; i < changedIndices.length; i++) + JSCompiler_temp.push(touches[changedIndices[i]]); + for ( + changedIndices = 0; + changedIndices < JSCompiler_temp.length; + changedIndices++ + ) { + i = JSCompiler_temp[changedIndices]; + i.changedTouches = JSCompiler_temp; + i.touches = touches; + index = null; + var target = i.target; + null === target || void 0 === target || 1 > target || (index = target); + _receiveRootNodeIDEvent(index, eventTopLevelType, i); + } + } +}); +getFiberCurrentPropsFromNode = function(stateNode) { + return instanceProps[stateNode._nativeTag] || null; +}; +getInstanceFromNode = getInstanceFromTag; +getNodeFromInstance = function(inst) { + var tag = inst.stateNode._nativeTag; + void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); + if (!tag) throw ReactError("All native instances should have a tag."); + return tag; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var ReactNativeFiberHostComponent = (function() { + function ReactNativeFiberHostComponent(tag, viewConfig) { + if (!(this instanceof ReactNativeFiberHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; + } + ReactNativeFiberHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.measure = function(callback) { + ReactNativePrivateInterface.UIManager.measure( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { + ReactNativePrivateInterface.UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var relativeNode = void 0; + "number" === typeof relativeToNativeNode + ? (relativeNode = relativeToNativeNode) + : relativeToNativeNode._nativeTag + ? (relativeNode = relativeToNativeNode._nativeTag) + : relativeToNativeNode.canonical && + relativeToNativeNode.canonical._nativeTag && + (relativeNode = relativeToNativeNode.canonical._nativeTag); + null != relativeNode && + ReactNativePrivateInterface.UIManager.measureLayout( + this._nativeTag, + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactNativeFiberHostComponent.prototype.setNativeProps = function( + nativeProps + ) { + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + this.viewConfig.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + nativeProps + ); + }; + return ReactNativeFiberHostComponent; +})(); +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, + nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + 1 === tag % 10 && (tag += 2); + nextReactTag = tag + 2; + return tag; +} +function recursivelyUncacheFiberNode(node) { + if ("number" === typeof node) + delete instanceCache[node], delete instanceProps[node]; + else { + var tag = node._nativeTag; + delete instanceCache[tag]; + delete instanceProps[tag]; + node._children.forEach(recursivelyUncacheFiberNode); + } +} +function finalizeInitialChildren(parentInstance) { + if (0 === parentInstance._children.length) return !1; + var nativeTags = parentInstance._children.map(function(child) { + return "number" === typeof child ? child : child._nativeTag; + }); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); + return !1; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout, + BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +var isDevToolsPresent = "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__; +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_shouldYield = Scheduler.unstable_shouldYield, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; +if ( + null == tracing.__interactionsRef || + null == tracing.__interactionsRef.current +) + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); +var fakeCallbackNode = {}, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; + this.actualDuration = 0; + this.actualStartTime = -1; + this.treeBaseDuration = this.selfBaseDuration = 0; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null), + (workInProgress.actualDuration = 0), + (workInProgress.actualStartTime = -1)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue, providerFiber); + context._currentValue = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + now$1 = Scheduler.unstable_now, + commitTime = 0, + profilerStartTime = -1; +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (0 <= profilerStartTime) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + overrideBaseTime && (fiber.selfBaseDuration = elapsedTime); + profilerStartTime = -1; + } +} +var hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + if ( + didCaptureError && + "function" !== typeof Component.getDerivedStateFromError + ) { + var nextChildren = null; + profilerStartTime = -1; + } else nextChildren = shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((didCaptureError = nextChildren), + (workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + didCaptureError, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + renderExpirationTime = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = renderExpirationTime; + mode = current$$1; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else { + if (null !== current$$1.memoizedState) + if ( + ((nextFallbackChildren = current$$1.child), + (mode = nextFallbackChildren.sibling), + nextDidTimeout) + ) { + nextProps = nextProps.fallback; + renderExpirationTime = createWorkInProgress( + nextFallbackChildren, + nextFallbackChildren.pendingProps, + 0 + ); + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== nextFallbackChildren.child && + (renderExpirationTime.child = nextDidTimeout)); + if (workInProgress.mode & 4) { + nextFallbackChildren = 0; + for ( + nextDidTimeout = renderExpirationTime.child; + null !== nextDidTimeout; + + ) + (nextFallbackChildren += nextDidTimeout.treeBaseDuration), + (nextDidTimeout = nextDidTimeout.sibling); + renderExpirationTime.treeBaseDuration = nextFallbackChildren; + } + nextFallbackChildren = renderExpirationTime.sibling = createWorkInProgress( + mode, + nextProps, + mode.expirationTime + ); + mode = renderExpirationTime; + renderExpirationTime.childExpirationTime = 0; + renderExpirationTime = nextFallbackChildren; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren.child, + nextProps.children, + renderExpirationTime + ); + else { + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + nextProps = nextProps.fallback; + nextFallbackChildren = createFiberFromFragment(null, mode, 0, null); + nextFallbackChildren.child = _currentPrimaryChild; + 0 === (workInProgress.mode & 1) && + (nextFallbackChildren.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + if (workInProgress.mode & 4) { + nextDidTimeout = 0; + for ( + _currentPrimaryChild = nextFallbackChildren.child; + null !== _currentPrimaryChild; + + ) + (nextDidTimeout += _currentPrimaryChild.treeBaseDuration), + (_currentPrimaryChild = _currentPrimaryChild.sibling); + nextFallbackChildren.treeBaseDuration = nextDidTimeout; + } + renderExpirationTime = nextFallbackChildren.sibling = createFiberFromFragment( + nextProps, + mode, + renderExpirationTime, + null + ); + renderExpirationTime.effectTag |= 2; + mode = nextFallbackChildren; + nextFallbackChildren.childExpirationTime = 0; + mode.return = renderExpirationTime.return = workInProgress; + } else + renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + nextProps.children, + renderExpirationTime + ); + } + workInProgress.stateNode = current$$1.stateNode; + } + workInProgress.memoizedState = nextState; + workInProgress.child = mode; + return renderExpirationTime; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + profilerStartTime = -1; + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function(parent, workInProgress) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag || 6 === node.tag) parent._children.push(node.stateNode); + else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +updateHostContainer = function() {}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + current.memoizedProps !== newProps && + (requiredContext(contextStackCursor$1.current), + (workInProgress.updateQueue = UPDATE_SIGNAL)) && + (workInProgress.effectTag |= 4); +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && (workInProgress.effectTag |= 4); +}; +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + newProps = workInProgress.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + workInProgress.effectTag &= -3; + updateHostContainer(workInProgress); + break; + case 5: + popHostContext(workInProgress); + renderExpirationTime = requiredContext(rootInstanceStackCursor.current); + var type = workInProgress.type; + if (null !== current && null != workInProgress.stateNode) + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + renderExpirationTime + ), + current.ref !== workInProgress.ref && + (workInProgress.effectTag |= 128); + else if (newProps) { + current = requiredContext(contextStackCursor$1.current); + var tag = allocateTag(), + viewConfig = getViewConfigForType(type), + updatePayload = diffProperties( + null, + emptyObject, + newProps, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.createView( + tag, + viewConfig.uiViewClassName, + renderExpirationTime, + updatePayload + ); + viewConfig = new ReactNativeFiberHostComponent(tag, viewConfig); + instanceCache[tag] = workInProgress; + instanceProps[tag] = newProps; + appendAllChildren(viewConfig, workInProgress, !1, !1); + finalizeInitialChildren( + viewConfig, + type, + newProps, + renderExpirationTime, + current + ) && (workInProgress.effectTag |= 4); + workInProgress.stateNode = viewConfig; + null !== workInProgress.ref && (workInProgress.effectTag |= 128); + } else if (null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != workInProgress.stateNode) + updateHostText$1( + current, + workInProgress, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + if (!requiredContext(contextStackCursor$1.current).isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + renderExpirationTime = allocateTag(); + ReactNativePrivateInterface.UIManager.createView( + renderExpirationTime, + "RCTRawText", + current, + { text: newProps } + ); + instanceCache[renderExpirationTime] = workInProgress; + workInProgress.stateNode = renderExpirationTime; + } + break; + case 11: + break; + case 13: + newProps = workInProgress.memoizedState; + if (0 !== (workInProgress.effectTag & 64)) + return ( + (workInProgress.expirationTime = renderExpirationTime), workInProgress + ); + newProps = null !== newProps; + renderExpirationTime = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (current = current.child.sibling), + null !== current && + ((type = workInProgress.firstEffect), + null !== type + ? ((workInProgress.firstEffect = current), + (current.nextEffect = type)) + : ((workInProgress.firstEffect = workInProgress.lastEffect = current), + (current.nextEffect = null)), + (current.effectTag = 8)))); + newProps && + !renderExpirationTime && + 0 !== (workInProgress.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + if (newProps || renderExpirationTime) workInProgress.effectTag |= 4; + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case 10: + popProvider(workInProgress); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + return null; +} +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function hideOrUnhideAllChildren(finishedWork, isHidden) { + for (var node = finishedWork; ; ) { + if (5 === node.tag) { + var instance = node.stateNode; + if (isHidden) { + var viewConfig = instance.viewConfig; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } else { + instance = node.stateNode; + updatePayload = node.memoizedProps; + viewConfig = instance.viewConfig; + var prevProps = Object.assign({}, updatePayload, { + style: [updatePayload.style, { display: "none" }] + }); + updatePayload = diffProperties( + null, + prevProps, + updatePayload, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + } else { + if (6 === node.tag) throw Error("Not yet implemented."); + if (13 === node.tag && null !== node.memoizedState) { + instance = node.child.sibling; + instance.return = node; + node = instance; + continue; + } else if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitUnmount(current$$1$jscomp$0) { + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(current$$1$jscomp$0); + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = current$$1$jscomp$0.updateQueue; + if ( + null !== updateQueue && + ((updateQueue = updateQueue.lastEffect), null !== updateQueue) + ) { + var effect = (updateQueue = updateQueue.next); + do { + var destroy = effect.destroy; + if (void 0 !== destroy) { + var current$$1 = current$$1$jscomp$0; + try { + destroy(); + } catch (error) { + captureCommitPhaseError(current$$1, error); + } + } + effect = effect.next; + } while (effect !== updateQueue); + } + break; + case 1: + safelyDetachRef(current$$1$jscomp$0); + updateQueue = current$$1$jscomp$0.stateNode; + if ("function" === typeof updateQueue.componentWillUnmount) + try { + (updateQueue.props = current$$1$jscomp$0.memoizedProps), + (updateQueue.state = current$$1$jscomp$0.memoizedState), + updateQueue.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(current$$1$jscomp$0, unmountError); + } + break; + case 5: + safelyDetachRef(current$$1$jscomp$0); + break; + case 4: + unmountHostComponents(current$$1$jscomp$0); + } +} +function isHostParent(fiber) { + return 5 === fiber.tag || 3 === fiber.tag || 4 === fiber.tag; +} +function commitPlacement(finishedWork) { + a: { + for (var parent = finishedWork.return; null !== parent; ) { + if (isHostParent(parent)) { + var parentFiber = parent; + break a; + } + parent = parent.return; + } + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + switch (parentFiber.tag) { + case 5: + parent = parentFiber.stateNode; + var isContainer = !1; + break; + case 3: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + case 4: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + default: + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + parentFiber.effectTag & 16 && (parentFiber.effectTag &= -17); + a: b: for (parentFiber = finishedWork; ; ) { + for (; null === parentFiber.sibling; ) { + if (null === parentFiber.return || isHostParent(parentFiber.return)) { + parentFiber = null; + break a; + } + parentFiber = parentFiber.return; + } + parentFiber.sibling.return = parentFiber.return; + for ( + parentFiber = parentFiber.sibling; + 5 !== parentFiber.tag && 6 !== parentFiber.tag && 18 !== parentFiber.tag; + + ) { + if (parentFiber.effectTag & 2) continue b; + if (null === parentFiber.child || 4 === parentFiber.tag) continue b; + else + (parentFiber.child.return = parentFiber), + (parentFiber = parentFiber.child); + } + if (!(parentFiber.effectTag & 2)) { + parentFiber = parentFiber.stateNode; + break a; + } + } + for (var node = finishedWork; ; ) { + if (5 === node.tag || 6 === node.tag) { + var stateNode = node.stateNode; + if (parentFiber) + if (isContainer) { + if ("number" === typeof parent) + throw ReactError( + "Container does not support insertBefore operation" + ); + } else { + var parentInstance = parent, + beforeChild = parentFiber, + children = parentInstance._children, + index = children.indexOf(stateNode); + 0 <= index + ? (children.splice(index, 1), + (beforeChild = children.indexOf(beforeChild)), + children.splice(beforeChild, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [index], + [beforeChild], + [], + [], + [] + )) + : ((index = children.indexOf(beforeChild)), + children.splice(index, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [ + "number" === typeof stateNode + ? stateNode + : stateNode._nativeTag + ], + [index], + [] + )); + } + else + isContainer + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ + "number" === typeof stateNode ? stateNode : stateNode._nativeTag + ]) + : ((parentInstance = parent), + (children = + "number" === typeof stateNode ? stateNode : stateNode._nativeTag), + (index = parentInstance._children), + (beforeChild = index.indexOf(stateNode)), + 0 <= beforeChild + ? (index.splice(beforeChild, 1), + index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [beforeChild], + [index.length - 1], + [], + [], + [] + )) + : (index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [children], + [index.length - 1], + [] + ))); + } else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function unmountHostComponents(current$$1) { + for ( + var node = current$$1, + currentParentIsValid = !1, + currentParent = void 0, + currentParentIsContainer = void 0; + ; + + ) { + if (!currentParentIsValid) { + currentParentIsValid = node.return; + a: for (;;) { + if (null === currentParentIsValid) + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + switch (currentParentIsValid.tag) { + case 5: + currentParent = currentParentIsValid.stateNode; + currentParentIsContainer = !1; + break a; + case 3: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + case 4: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + } + currentParentIsValid = currentParentIsValid.return; + } + currentParentIsValid = !0; + } + if (5 === node.tag || 6 === node.tag) { + a: for (var root = node, node$jscomp$0 = root; ; ) + if ( + (commitUnmount(node$jscomp$0), + null !== node$jscomp$0.child && 4 !== node$jscomp$0.tag) + ) + (node$jscomp$0.child.return = node$jscomp$0), + (node$jscomp$0 = node$jscomp$0.child); + else { + if (node$jscomp$0 === root) break; + for (; null === node$jscomp$0.sibling; ) { + if (null === node$jscomp$0.return || node$jscomp$0.return === root) + break a; + node$jscomp$0 = node$jscomp$0.return; + } + node$jscomp$0.sibling.return = node$jscomp$0.return; + node$jscomp$0 = node$jscomp$0.sibling; + } + if (currentParentIsContainer) + (root = currentParent), + recursivelyUncacheFiberNode(node.stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); + else { + root = currentParent; + var child = node.stateNode; + recursivelyUncacheFiberNode(child); + node$jscomp$0 = root._children; + child = node$jscomp$0.indexOf(child); + node$jscomp$0.splice(child, 1); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); + } + } else if (4 === node.tag) { + if (null !== node.child) { + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = !0; + node.child.return = node; + node = node.child; + continue; + } + } else if ((commitUnmount(node), null !== node.child)) { + node.child.return = node; + node = node.child; + continue; + } + if (node === current$$1) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === current$$1) return; + node = node.return; + 4 === node.tag && (currentParentIsValid = !1); + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + break; + case 1: + break; + case 5: + var instance = finishedWork.stateNode; + if (null != instance) { + var newProps = finishedWork.memoizedProps; + current$$1 = null !== current$$1 ? current$$1.memoizedProps : newProps; + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + null !== updatePayload && + ((finishedWork = instance.viewConfig), + (instanceProps[instance._nativeTag] = newProps), + (newProps = diffProperties( + null, + current$$1, + newProps, + finishedWork.validAttributes + )), + null != newProps && + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + finishedWork.uiViewClassName, + newProps + )); + } + break; + case 6: + if (null === finishedWork.stateNode) + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); + break; + case 20: + break; + case 3: + break; + case 12: + break; + case 13: + commitSuspenseComponent(finishedWork); + break; + case 17: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState, + newDidTimeout = void 0, + primaryChildParent = finishedWork; + null === newState + ? (newDidTimeout = !1) + : ((newDidTimeout = !0), + (primaryChildParent = finishedWork.child), + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500)); + null !== primaryChildParent && + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + ((retry = tracing.unstable_wrap(retry)), + retryCache.add(thenable), + thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + pendingPassiveEffectsExpirationTime = 0, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } + schedulePendingInteraction(root, expirationTime); +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + if ( + root$jscomp$0 !== workInProgressRoot || + expirationTime !== renderExpirationTime + ) + prepareFreshStack(root$jscomp$0, expirationTime), + startWorkOnPendingInteraction(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root$jscomp$0.memoizedInteractions; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + (tracing.__interactionsRef.current = prevInteractions), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !Scheduler_shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + currentTime.mode & 4 && + stopProfilerTimerIfRunningAndRecordDelta(currentTime, !0); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + (sourceFiber = tracing.unstable_wrap(sourceFiber)), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + tracing.__interactionsRef.current = prevInteractions; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var current$$1 = unitOfWork.alternate; + 0 !== (unitOfWork.mode & 4) + ? ((profilerStartTime = now$1()), + 0 > unitOfWork.actualStartTime && (unitOfWork.actualStartTime = now$1()), + (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)), + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, !0)) + : (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === current$$1 && (current$$1 = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return current$$1; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + if (0 === (workInProgress.mode & 4)) + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + else { + var fiber = workInProgress; + profilerStartTime = now$1(); + 0 > fiber.actualStartTime && (fiber.actualStartTime = now$1()); + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + } + fiber = workInProgress; + if (1 === renderExpirationTime || 1 !== fiber.childExpirationTime) { + var newChildExpirationTime = 0; + if (0 !== (fiber.mode & 4)) { + for ( + var actualDuration = fiber.actualDuration, + treeBaseDuration = fiber.selfBaseDuration, + shouldBubbleActualDurations = + null === fiber.alternate || + fiber.child !== fiber.alternate.child, + child = fiber.child; + null !== child; + + ) { + var childUpdateExpirationTime = child.expirationTime, + childChildExpirationTime = child.childExpirationTime; + childUpdateExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childUpdateExpirationTime); + childChildExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childChildExpirationTime); + shouldBubbleActualDurations && + (actualDuration += child.actualDuration); + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + fiber.actualDuration = actualDuration; + fiber.treeBaseDuration = treeBaseDuration; + } else + for (actualDuration = fiber.child; null !== actualDuration; ) + (treeBaseDuration = actualDuration.expirationTime), + (shouldBubbleActualDurations = + actualDuration.childExpirationTime), + treeBaseDuration > newChildExpirationTime && + (newChildExpirationTime = treeBaseDuration), + shouldBubbleActualDurations > newChildExpirationTime && + (newChildExpirationTime = shouldBubbleActualDurations), + (actualDuration = actualDuration.sibling); + fiber.childExpirationTime = newChildExpirationTime; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (0 !== (workInProgress.mode & 4)) { + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + fiber = workInProgress.actualDuration; + for ( + newChildExpirationTime = workInProgress.child; + null !== newChildExpirationTime; + + ) + (fiber += newChildExpirationTime.actualDuration), + (newChildExpirationTime = newChildExpirationTime.sibling); + workInProgress.actualDuration = fiber; + } + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + if (1 < finishedWork.effectTag) + if (null !== finishedWork.lastEffect) { + finishedWork.lastEffect.nextEffect = finishedWork; + var firstEffect = finishedWork.firstEffect; + } else firstEffect = finishedWork; + else firstEffect = finishedWork.firstEffect; + if (null !== firstEffect) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + childExpirationTimeBeforeCommit = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + ReactCurrentOwner$2.current = null; + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + commitTime = now$1(); + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + break; + case 6: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + unmountHostComponents(current$$1); + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = firstEffect; + do + try { + for ( + effectTag = root, current$$1$jscomp$0 = expirationTime; + null !== nextEffect; + + ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + current$$1 = effectTag; + var current$$1$jscomp$1 = nextEffect.alternate; + currentRef = nextEffect; + alternate = current$$1$jscomp$0; + switch (currentRef.tag) { + case 0: + case 11: + case 15: + commitHookEffectList(UnmountLayout, MountLayout, currentRef); + break; + case 1: + var instance$jscomp$0 = currentRef.stateNode; + if (currentRef.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$0.componentDidMount(); + else { + var prevProps$jscomp$0 = + currentRef.elementType === currentRef.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + currentRef.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$0.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$0.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue = currentRef.updateQueue; + null !== updateQueue && + commitUpdateQueue( + currentRef, + updateQueue, + instance$jscomp$0, + alternate + ); + break; + case 3: + var _updateQueue = currentRef.updateQueue; + if (null !== _updateQueue) { + current$$1 = null; + if (null !== currentRef.child) + switch (currentRef.child.tag) { + case 5: + current$$1 = currentRef.child.stateNode; + break; + case 1: + current$$1 = currentRef.child.stateNode; + } + commitUpdateQueue( + currentRef, + _updateQueue, + current$$1, + alternate + ); + } + break; + case 5: + break; + case 6: + break; + case 4: + break; + case 12: + var onRender = currentRef.memoizedProps.onRender; + onRender( + currentRef.memoizedProps.id, + null === current$$1$jscomp$1 ? "mount" : "update", + currentRef.actualDuration, + currentRef.treeBaseDuration, + currentRef.actualStartTime, + commitTime, + current$$1.memoizedInteractions + ); + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$1 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$1; + break; + default: + instanceToUse = instance$jscomp$1; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + tracing.__interactionsRef.current = childExpirationTimeBeforeCommit; + workPhase = updateExpirationTimeBeforeCommit; + } else (root.current = finishedWork), (commitTime = now$1()); + rootDoesHavePassiveEffects + ? ((rootDoesHavePassiveEffects = !1), + (rootWithPendingPassiveEffects = root), + (pendingPassiveEffectsExpirationTime = expirationTime)) + : finishPendingInteractions(root, expirationTime); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects, + expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = 0; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (var effect = root.current.firstEffect; null !== effect; ) { + try { + var finishedWork = effect; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === effect) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(effect, error); + } + effect = effect.nextEffect; + } + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 12: + workInProgress.effectTag |= 4; + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + (workInProgress.effectTag |= 4), + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function schedulePendingInteraction(root, expirationTime) { + var interactions = tracing.__interactionsRef.current; + if (0 < interactions.size) { + var pendingInteractionMap = root.pendingInteractionMap, + pendingInteractions = pendingInteractionMap.get(expirationTime); + null != pendingInteractions + ? interactions.forEach(function(interaction) { + pendingInteractions.has(interaction) || interaction.__count++; + pendingInteractions.add(interaction); + }) + : (pendingInteractionMap.set(expirationTime, new Set(interactions)), + interactions.forEach(function(interaction) { + interaction.__count++; + })); + pendingInteractionMap = tracing.__subscriberRef.current; + if (null !== pendingInteractionMap) + pendingInteractionMap.onWorkScheduled( + interactions, + 1e3 * expirationTime + root.interactionThreadID + ); + } +} +function startWorkOnPendingInteraction(root, expirationTime) { + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime >= expirationTime && + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + }); + root.memoizedInteractions = interactions; + if (0 < interactions.size) { + var subscriber = tracing.__subscriberRef.current; + if (null !== subscriber) { + root = 1e3 * expirationTime + root.interactionThreadID; + try { + subscriber.onWorkStarted(interactions, root); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + } + } +} +function finishPendingInteractions(root, committedExpirationTime) { + var earliestRemainingTimeAfterCommit = root.firstPendingTime, + subscriber = void 0; + try { + if ( + ((subscriber = tracing.__subscriberRef.current), + null !== subscriber && 0 < root.memoizedInteractions.size) + ) + subscriber.onWorkStopped( + root.memoizedInteractions, + 1e3 * committedExpirationTime + root.interactionThreadID + ); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } finally { + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime > earliestRemainingTimeAfterCommit && + (pendingInteractionMap.delete(scheduledExpirationTime), + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + if (null !== subscriber && 0 === interaction.__count) + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + })); + }); + } +} +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactNativeRenderer = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function(handle, nativeProps) { + null != handle._nativeTag && + ((nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + handle.viewConfig.validAttributes + )), + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + handle._nativeTag, + handle.viewConfig.uiViewClassName, + nativeProps + )); + }, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = 0; + isDevToolsPresent && (uninitializedFiber |= 4); + uninitializedFiber = createFiber(3, null, null, uninitializedFiber); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + unmountComponentAtNodeAndRemoveContainer: function(containerTag) { + ReactNativeRenderer.unmountComponentAtNode(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + unstable_batchedUpdates: batchedUpdates, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance), + computeComponentStackForErrorReporting: function(reactTag) { + return (reactTag = getInstanceFromTag(reactTag)) + ? getStackByFiberInDevAndProd(reactTag) + : ""; + } + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactNativeRenderer$2 = { default: ReactNativeRenderer }, + ReactNativeRenderer$3 = + (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; +module.exports = ReactNativeRenderer$3.default || ReactNativeRenderer$3; diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-profiling.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js similarity index 98% rename from Libraries/Renderer/oss/ReactNativeRenderer-profiling.js rename to Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js index 5a356fca8b050c..0df2e6154a6b70 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-profiling.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js @@ -11,17 +11,11 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), - RCTEventEmitter = require("RCTEventEmitter"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), Scheduler = require("scheduler"), - tracing = require("scheduler/tracing"), - ExceptionsManager = require("ExceptionsManager"); + tracing = require("scheduler/tracing"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -618,7 +612,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -681,7 +675,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -710,12 +704,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -801,7 +795,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -811,7 +805,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -823,7 +817,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -837,7 +831,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -867,11 +861,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -925,9 +919,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -949,8 +943,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -958,10 +959,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1061,7 +1060,7 @@ function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { } }); } -RCTEventEmitter.register({ +ReactNativePrivateInterface.RCTEventEmitter.register({ receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); }, @@ -1111,8 +1110,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) - : UIManager.clearJSResponder(); + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1376,14 +1378,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1451,7 +1453,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1463,7 +1465,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1528,19 +1530,19 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig = viewConfig; } ReactNativeFiberHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.measure = function(callback) { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1559,7 +1561,7 @@ var ReactNativeFiberHostComponent = (function() { relativeToNativeNode.canonical._nativeTag && (relativeNode = relativeToNativeNode.canonical._nativeTag); null != relativeNode && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( this._nativeTag, relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1576,7 +1578,7 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( this._nativeTag, this.viewConfig.uiViewClassName, nativeProps @@ -1589,7 +1591,9 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var UPDATE_SIGNAL = {}, +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, nextReactTag = 3; function allocateTag() { var tag = nextReactTag; @@ -1612,7 +1616,10 @@ function finalizeInitialChildren(parentInstance) { var nativeTags = parentInstance._children.map(function(child) { return "number" === typeof child ? child : child._nativeTag; }); - UIManager.setChildren(parentInstance._nativeTag, nativeTags); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); return !1; } var scheduleTimeout = setTimeout, @@ -4621,14 +4628,14 @@ function completeWork(current, workInProgress, renderExpirationTime) { else if (newProps) { current = requiredContext(contextStackCursor$1.current); var tag = allocateTag(), - viewConfig = ReactNativeViewConfigRegistry.get(type), + viewConfig = getViewConfigForType(type), updatePayload = diffProperties( null, emptyObject, newProps, viewConfig.validAttributes ); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, viewConfig.uiViewClassName, renderExpirationTime, @@ -4671,9 +4678,12 @@ function completeWork(current, workInProgress, renderExpirationTime) { "Text strings must be rendered within a component." ); renderExpirationTime = allocateTag(); - UIManager.createView(renderExpirationTime, "RCTRawText", current, { - text: newProps - }); + ReactNativePrivateInterface.UIManager.createView( + renderExpirationTime, + "RCTRawText", + current, + { text: newProps } + ); instanceCache[renderExpirationTime] = workInProgress; workInProgress.stateNode = renderExpirationTime; } @@ -4769,7 +4779,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -4841,7 +4851,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { { style: { display: "none" } }, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4859,7 +4869,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { updatePayload, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -5012,7 +5022,7 @@ function commitPlacement(finishedWork) { ? (children.splice(index, 1), (beforeChild = children.indexOf(beforeChild)), children.splice(beforeChild, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [index], [beforeChild], @@ -5022,7 +5032,7 @@ function commitPlacement(finishedWork) { )) : ((index = children.indexOf(beforeChild)), children.splice(index, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -5037,7 +5047,7 @@ function commitPlacement(finishedWork) { } else isContainer - ? UIManager.setChildren(parent, [ + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ "number" === typeof stateNode ? stateNode : stateNode._nativeTag ]) : ((parentInstance = parent), @@ -5048,7 +5058,7 @@ function commitPlacement(finishedWork) { 0 <= beforeChild ? (index.splice(beforeChild, 1), index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [beforeChild], [index.length - 1], @@ -5057,7 +5067,7 @@ function commitPlacement(finishedWork) { [] )) : (index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -5134,7 +5144,14 @@ function unmountHostComponents(current$$1) { if (currentParentIsContainer) (root = currentParent), recursivelyUncacheFiberNode(node.stateNode), - UIManager.manageChildren(root, [], [], [], [], [0]); + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); else { root = currentParent; var child = node.stateNode; @@ -5142,7 +5159,14 @@ function unmountHostComponents(current$$1) { node$jscomp$0 = root._children; child = node$jscomp$0.indexOf(child); node$jscomp$0.splice(child, 1); - UIManager.manageChildren(root._nativeTag, [], [], [], [], [child]); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); } } else if (4 === node.tag) { if (null !== node.child) { @@ -5194,7 +5218,7 @@ function commitWork(current$$1, finishedWork) { finishedWork.validAttributes )), null != newProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, finishedWork.uiViewClassName, newProps @@ -5206,9 +5230,11 @@ function commitWork(current$$1, finishedWork) { throw ReactError( "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - UIManager.updateView(finishedWork.stateNode, "RCTRawText", { - text: finishedWork.memoizedProps - }); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); break; case 20: break; @@ -7137,10 +7163,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -7153,7 +7183,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7169,7 +7199,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7191,7 +7221,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7215,7 +7245,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7235,7 +7265,7 @@ var roots = new Map(), handle.viewConfig.validAttributes )), null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( handle._nativeTag, handle.viewConfig.uiViewClassName, nativeProps @@ -7273,7 +7303,7 @@ var roots = new Map(), }, unmountComponentAtNodeAndRemoveContainer: function(containerTag) { ReactNativeRenderer.unmountComponentAtNode(containerTag); - UIManager.removeRootView(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); }, createPortal: function(children, containerTag) { return createPortal( @@ -7298,7 +7328,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7314,7 +7344,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7332,7 +7362,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7356,7 +7386,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7364,10 +7394,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance), diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 5cea0e09037851..8f6a708fd20579 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -10,7 +10,7 @@ 'use strict'; -const BatchedBridge = require('../../BatchedBridge/BatchedBridge'); +import {BatchedBridge} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; // TODO @sema: Adjust types import type {ReactNativeType} from './ReactNativeTypes'; @@ -18,9 +18,9 @@ import type {ReactNativeType} from './ReactNativeTypes'; let ReactFabric; if (__DEV__) { - ReactFabric = require('ReactFabric-dev'); + ReactFabric = require('../implementations/ReactFabric-dev'); } else { - ReactFabric = require('ReactFabric-prod'); + ReactFabric = require('../implementations/ReactFabric-prod'); } BatchedBridge.registerCallableModule('ReactFabric', ReactFabric); diff --git a/Libraries/Renderer/shims/ReactFeatureFlags.js b/Libraries/Renderer/shims/ReactFeatureFlags.js new file mode 100644 index 00000000000000..86feb9c0228212 --- /dev/null +++ b/Libraries/Renderer/shims/ReactFeatureFlags.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const ReactFeatureFlags = { + debugRenderPhaseSideEffects: false, +}; + +module.exports = ReactFeatureFlags; diff --git a/Libraries/Renderer/shims/ReactNative.js b/Libraries/Renderer/shims/ReactNative.js index 857858e55bd39a..9f471e4107a7ee 100644 --- a/Libraries/Renderer/shims/ReactNative.js +++ b/Libraries/Renderer/shims/ReactNative.js @@ -15,9 +15,9 @@ import type {ReactNativeType} from './ReactNativeTypes'; let ReactNative; if (__DEV__) { - ReactNative = require('ReactNativeRenderer-dev'); + ReactNative = require('../implementations/ReactNativeRenderer-dev'); } else { - ReactNative = require('ReactNativeRenderer-prod'); + ReactNative = require('../implementations/ReactNativeRenderer-prod'); } module.exports = (ReactNative: ReactNativeType); diff --git a/Libraries/Renderer/shims/createReactNativeComponentClass.js b/Libraries/Renderer/shims/createReactNativeComponentClass.js index c632a3c0fbb35a..86a758d918b483 100644 --- a/Libraries/Renderer/shims/createReactNativeComponentClass.js +++ b/Libraries/Renderer/shims/createReactNativeComponentClass.js @@ -10,9 +10,11 @@ 'use strict'; +import {ReactNativeViewConfigRegistry} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; + import type {ViewConfigGetter} from './ReactNativeTypes'; -const {register} = require('./ReactNativeViewConfigRegistry'); +const {register} = ReactNativeViewConfigRegistry; /** * Creates a renderable ReactNative host component. From 2dd7dd8e45f9d4a1086f84d5b70ea66406d98439 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 5 Jun 2019 04:58:11 -0700 Subject: [PATCH 100/330] Removed autoresizing mask for modal host container view (#25150) Summary: Fixes #18177 . Related #24497. Autoresizing mask would conflict with `AutoLayout`. For example , it would impact `SafeAreaView`. And actually we don't need to use autoresizing mask, we observe the bounds change notification and [update the frame manually](https://github.com/facebook/react-native/blob/1151c096dab17e5d9a6ac05b61aacecd4305f3db/React/Views/RCTModalHostView.m#L59). ## Changelog [iOS] [Fixed] - Removed autoresizing mask for modal host container view Pull Request resolved: https://github.com/facebook/react-native/pull/25150 Differential Revision: D15645148 Pulled By: cpojer fbshipit-source-id: 95d5f40feaa980b959a3de6e273dccac8158c57b --- React/Views/RCTModalHostView.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m index f586e4ad0eadb5..bc0cac18b3ec94 100644 --- a/React/Views/RCTModalHostView.m +++ b/React/Views/RCTModalHostView.m @@ -129,8 +129,6 @@ - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex [subview addGestureRecognizer:_menuButtonGestureRecognizer]; } #endif - subview.autoresizingMask = UIViewAutoresizingFlexibleHeight | - UIViewAutoresizingFlexibleWidth; [_modalViewController.view insertSubview:subview atIndex:0]; _reactSubview = subview; From 68bca1fbd042f87ec29b65abf8ebb3e4a8234bc1 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 5 Jun 2019 05:08:59 -0700 Subject: [PATCH 101/330] Excluded tests file from JSI pod (#25151) Summary: Tests file exposed in https://github.com/facebook/react-native/commit/608b1b5ea2d9861816aaf3c4289e4316d9304b87. This break e2e tests, so let's excluded them from JSI pod. ## Changelog [iOS] [Fixed] - Excluded tests file from JSI pod Pull Request resolved: https://github.com/facebook/react-native/pull/25151 Differential Revision: D15645046 Pulled By: cpojer fbshipit-source-id: 19c712e4307cf712b8377d721661a2b476151732 --- ReactCommon/React-Fabric.podspec | 2 +- ReactCommon/jsi/React-jsi.podspec | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ReactCommon/React-Fabric.podspec b/ReactCommon/React-Fabric.podspec index 9fe685f5701775..ea8116e2cec922 100644 --- a/ReactCommon/React-Fabric.podspec +++ b/ReactCommon/React-Fabric.podspec @@ -69,7 +69,7 @@ Pod::Spec.new do |s| ss.dependency folly_dep_name, folly_version ss.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags ss.source_files = "fabric/core/**/*.{m,mm,cpp,h}" - ss.exclude_files = "**/tests/*" + ss.exclude_files = "**/tests/**/*" ss.header_dir = "react/core" ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } end diff --git a/ReactCommon/jsi/React-jsi.podspec b/ReactCommon/jsi/React-jsi.podspec index 180905ca40b443..0b0ff66eb581e8 100644 --- a/ReactCommon/jsi/React-jsi.podspec +++ b/ReactCommon/jsi/React-jsi.podspec @@ -31,6 +31,7 @@ Pod::Spec.new do |s| s.platforms = { :ios => "9.0", :tvos => "9.2" } s.source = source s.source_files = "**/*.{cpp,h}" + s.exclude_files = "**/test/*" s.framework = "JavaScriptCore" s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/Folly\"" } From 995b4d30491d2336fed4a975e965668d9c8d5b7c Mon Sep 17 00:00:00 2001 From: Nate Date: Wed, 5 Jun 2019 06:09:09 -0700 Subject: [PATCH 102/330] Android Fix for 9145: No longer hard code build port (#23616) Summary: ### Problem According to https://github.com/facebook/react-native/issues/9145, the `--port` setting is not respected when executing `react-native run-android`. The templates that report things like what port the dev server runs on are hard coded as well. ### Solution This commit replaces the hardcoded instances of port 8081 on Android with a build configuration property. This allows setting of the port React Native Android connects to for the local build server. For this change to work, there must also be an update to the react native CLI to pass along this setting: https://github.com/react-native-community/react-native-cli/compare/master...nhunzaker:9145-android-no-port-hardcode-cli To avoid some noise on their end, I figured I wouldn't submit a PR until it's this approach is deemed workable. ## Changelog [Android][fixed] - `react-native run-android --port ` correctly connects to dev server and related error messages display the correct port Pull Request resolved: https://github.com/facebook/react-native/pull/23616 Differential Revision: D15645200 Pulled By: cpojer fbshipit-source-id: 3bdfd458b8ac3ec78290736c9ed0db2e5776ed46 --- ReactAndroid/build.gradle | 14 +++++++ .../facebook/react/bridge/JSBundleLoader.java | 4 +- .../react/common/DebugServerException.java | 19 ++++++---- .../react/devsupport/BundleDownloader.java | 8 ++-- .../react/devsupport/DevServerHelper.java | 7 ++-- .../systeminfo/AndroidInfoHelpers.java | 37 +++++++++++++++---- .../modules/systeminfo/AndroidInfoModule.java | 17 +++++++-- .../facebook/react/modules/systeminfo/BUCK | 3 ++ .../PackagerConnectionSettings.java | 12 +++--- ReactAndroid/src/main/res/BUCK | 9 +++++ .../src/main/res/systeminfo/values/values.xml | 5 +++ react.gradle | 16 ++++++++ 12 files changed, 119 insertions(+), 32 deletions(-) create mode 100644 ReactAndroid/src/main/res/systeminfo/values/values.xml diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 81e2d74ac759cd..f04bb4ad12db20 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -203,6 +203,16 @@ def findNdkBuildFullPath() { return null } +def reactNativeDevServerPort() { + def value = project.getProperties().get("reactNativeDevServerPort") + return value != null ? value : "8081" +} + +def reactNativeInspectorProxyPort() { + def value = project.getProperties().get("reactNativeInspectorProxyPort") + return value != null ? value : reactNativeDevServerPort() +} + def getNdkBuildFullPath() { def ndkBuildFullPath = findNdkBuildFullPath() if (ndkBuildFullPath == null) { @@ -288,6 +298,10 @@ android { buildConfigField("boolean", "IS_INTERNAL_BUILD", "false") buildConfigField("int", "EXOPACKAGE_FLAGS", "0") + + resValue "integer", "react_native_dev_server_port", reactNativeDevServerPort() + resValue "integer", "react_native_inspector_proxy_port", reactNativeInspectorProxyPort() + testApplicationId("com.facebook.react.tests.gradle") testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner") } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java index 3aff0da69e3026..9a67632c5c3661 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java @@ -72,7 +72,7 @@ public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false); return sourceURL; } catch (Exception e) { - throw DebugServerException.makeGeneric(e.getMessage(), e); + throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e); } } }; @@ -94,7 +94,7 @@ public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadScriptFromDeltaBundle(sourceURL, nativeDeltaClient, false); return sourceURL; } catch (Exception e) { - throw DebugServerException.makeGeneric(e.getMessage(), e); + throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e); } } }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java b/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java index bc2423b665b8ce..6c84a9bbc6f5f0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java +++ b/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java @@ -11,6 +11,7 @@ import java.io.IOException; +import android.net.Uri; import android.text.TextUtils; import com.facebook.common.logging.FLog; @@ -28,15 +29,19 @@ public class DebugServerException extends RuntimeException { "\u2022 Ensure that the packager server is running\n" + "\u2022 Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run 'adb devices' to see a list of connected devices\n" + "\u2022 Ensure Airplane Mode is disabled\n" + - "\u2022 If you're on a physical device connected to the same machine, run 'adb reverse tcp:8081 tcp:8081' to forward requests from your device\n" + - "\u2022 If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:8081\n\n"; + "\u2022 If you're on a physical device connected to the same machine, run 'adb reverse tcp: tcp:' to forward requests from your device\n" + + "\u2022 If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:\n\n"; - public static DebugServerException makeGeneric(String reason, Throwable t) { - return makeGeneric(reason, "", t); + public static DebugServerException makeGeneric(String url, String reason, Throwable t) { + return makeGeneric(url, reason, "", t); } - public static DebugServerException makeGeneric(String reason, String extra, Throwable t) { - return new DebugServerException(reason + GENERIC_ERROR_MESSAGE + extra, t); + public static DebugServerException makeGeneric(String url, String reason, String extra, Throwable t) { + Uri uri = Uri.parse(url); + + String message = GENERIC_ERROR_MESSAGE.replace("", String.valueOf(uri.getPort())); + + return new DebugServerException(reason + message + extra, t); } private DebugServerException(String description, String fileName, int lineNumber, int column) { @@ -56,7 +61,7 @@ public DebugServerException(String detailMessage, Throwable throwable) { * @param str json string returned by the debug server * @return A DebugServerException or null if the string is not of proper form. */ - @Nullable public static DebugServerException parse(String str) { + @Nullable public static DebugServerException parse(String url, String str) { if (TextUtils.isEmpty(str)) { return null; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java index ba798c14165ccc..e7a6fdb0cffd70 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java @@ -142,10 +142,12 @@ public void onFailure(Call call, IOException e) { } mDownloadBundleFromURLCall = null; + String url = call.request().url().toString(); + callback.onFailure( - DebugServerException.makeGeneric( + DebugServerException.makeGeneric(url, "Could not connect to development server.", - "URL: " + call.request().url().toString(), + "URL: " + url, e)); } @@ -284,7 +286,7 @@ private void processBundleResult( // Check for server errors. If the server error has the expected form, fail with more info. if (statusCode != 200) { String bodyString = body.readUtf8(); - DebugServerException debugServerException = DebugServerException.parse(bodyString); + DebugServerException debugServerException = DebugServerException.parse(url, bodyString); if (debugServerException != null) { callback.onFailure(debugServerException); } else { diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java index 2f70a32292ece7..deaffe8ed5baec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -8,6 +8,7 @@ package com.facebook.react.devsupport; import android.content.Context; +import android.content.res.Resources; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; @@ -261,7 +262,7 @@ protected Boolean doInBackground(Void... ignore) { public boolean doSync() { try { - String attachToNuclideUrl = getInspectorAttachUrl(title); + String attachToNuclideUrl = getInspectorAttachUrl(context, title); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(attachToNuclideUrl).build(); client.newCall(request).execute(); @@ -367,11 +368,11 @@ private String getInspectorDeviceUrl() { mPackageName); } - private String getInspectorAttachUrl(String title) { + private String getInspectorAttachUrl(Context context, String title) { return String.format( Locale.US, "http://%s/nuclide/attach-debugger-nuclide?title=%s&app=%s&device=%s", - AndroidInfoHelpers.getServerHost(), + AndroidInfoHelpers.getServerHost(context), title, mPackageName, AndroidInfoHelpers.getFriendlyDeviceName()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java index c336a7b5d6ada8..3659abaccc0ec7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java @@ -8,12 +8,14 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.util.Locale; +import android.content.Context; +import android.content.res.Resources; import android.os.Build; import com.facebook.common.logging.FLog; +import com.facebook.react.R; public class AndroidInfoHelpers { @@ -23,9 +25,6 @@ public class AndroidInfoHelpers { public static final String METRO_HOST_PROP_NAME = "metro.host"; - private static final int DEBUG_SERVER_HOST_PORT = 8081; - private static final int INSPECTOR_PROXY_PORT = 8081; - private static final String TAG = AndroidInfoHelpers.class.getSimpleName(); private static boolean isRunningOnGenymotion() { @@ -36,12 +35,24 @@ private static boolean isRunningOnStockEmulator() { return Build.FINGERPRINT.contains("generic"); } - public static String getServerHost() { - return getServerIpAddress(DEBUG_SERVER_HOST_PORT); + public static String getServerHost(Integer port) { + return getServerIpAddress(port); + } + + public static String getServerHost(Context context) { + return getServerIpAddress(getDevServerPort(context)); } - public static String getInspectorProxyHost() { - return getServerIpAddress(INSPECTOR_PROXY_PORT); + public static String getAdbReverseTcpCommand(Integer port) { + return "adb reverse tcp:" + port + " tcp:" + port; + } + + public static String getAdbReverseTcpCommand(Context context) { + return getAdbReverseTcpCommand(getDevServerPort(context)); + } + + public static String getInspectorProxyHost(Context context) { + return getServerIpAddress(getInspectorProxyPort(context)); } // WARNING(festevezga): This RN helper method has been copied to another FB-only target. Any changes should be applied to both. @@ -54,6 +65,16 @@ public static String getFriendlyDeviceName() { } } + private static Integer getDevServerPort(Context context) { + Resources resources = context.getResources(); + return resources.getInteger(R.integer.react_native_dev_server_port); + } + + private static Integer getInspectorProxyPort(Context context) { + Resources resources = context.getResources(); + return resources.getInteger(R.integer.react_native_dev_server_port); + } + private static String getServerIpAddress(int port) { // Since genymotion runs in vbox it use different hostname to refer to adb host. // We detect whether app runs on genymotion and replace js bundle server hostname accordingly diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java index 391dedccd869c5..cf5ca4036c5597 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java @@ -9,10 +9,13 @@ import android.annotation.SuppressLint; import android.app.UiModeManager; +import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Build; import android.provider.Settings.Secure; +import com.facebook.react.R; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.common.build.ReactBuildConfig; @@ -35,9 +38,7 @@ public class AndroidInfoModule extends ReactContextBaseJavaModule { public static final String NAME = "PlatformConstants"; private static final String IS_TESTING = "IS_TESTING"; - public AndroidInfoModule(ReactApplicationContext reactContext) { - super(reactContext); - } + public AndroidInfoModule(ReactApplicationContext reactContext) { super(reactContext); } /** * See: https://developer.android.com/reference/android/app/UiModeManager.html#getCurrentModeType() @@ -74,7 +75,7 @@ public String getName() { constants.put("Fingerprint", Build.FINGERPRINT); constants.put("Model", Build.MODEL); if (ReactBuildConfig.DEBUG) { - constants.put("ServerHost", AndroidInfoHelpers.getServerHost()); + constants.put("ServerHost", getServerHost()); } constants.put("isTesting", "true".equals(System.getProperty(IS_TESTING)) || isRunningScreenshotTest()); @@ -96,4 +97,12 @@ private Boolean isRunningScreenshotTest() { return false; } } + + private String getServerHost() { + Resources resources = getReactApplicationContext().getApplicationContext().getResources(); + + Integer devServerPort = resources.getInteger(R.integer.react_native_dev_server_port); + + return AndroidInfoHelpers.getServerHost(devServerPort); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK index 396d6c574e3046..433ecaf80863a3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK @@ -14,6 +14,7 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("res:systeminfo"), ], exported_deps = [ ":systeminfo-moduleless", @@ -29,8 +30,10 @@ rn_android_library( "PUBLIC", ], deps = [ + react_native_target("java/com/facebook/react/common:common"), react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("res:systeminfo"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java b/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java index 98ac8cff7f552e..a154553f0d06b1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java +++ b/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java @@ -7,13 +7,13 @@ package com.facebook.react.packagerconnection; -import javax.annotation.Nullable; - import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.text.TextUtils; +import javax.annotation.Nullable; + import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; import com.facebook.react.modules.systeminfo.AndroidInfoHelpers; @@ -24,10 +24,12 @@ public class PackagerConnectionSettings { private final SharedPreferences mPreferences; private final String mPackageName; + private final Context mAppContext; public PackagerConnectionSettings(Context applicationContext) { mPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext); mPackageName = applicationContext.getPackageName(); + mAppContext = applicationContext; } public String getDebugServerHost() { @@ -39,12 +41,12 @@ public String getDebugServerHost() { return Assertions.assertNotNull(hostFromSettings); } - String host = AndroidInfoHelpers.getServerHost(); + String host = AndroidInfoHelpers.getServerHost(mAppContext); if (host.equals(AndroidInfoHelpers.DEVICE_LOCALHOST)) { FLog.w( TAG, - "You seem to be running on device. Run 'adb reverse tcp:8081 tcp:8081' " + + "You seem to be running on device. Run '" + AndroidInfoHelpers.getAdbReverseTcpCommand(mAppContext) + "' " + "to forward the debug server's port to the device."); } @@ -52,7 +54,7 @@ public String getDebugServerHost() { } public String getInspectorServerHost() { - return AndroidInfoHelpers.getInspectorProxyHost(); + return AndroidInfoHelpers.getInspectorProxyHost(mAppContext); } public @Nullable String getPackageName() { diff --git a/ReactAndroid/src/main/res/BUCK b/ReactAndroid/src/main/res/BUCK index afb0be006d627c..9d24c6224833fe 100644 --- a/ReactAndroid/src/main/res/BUCK +++ b/ReactAndroid/src/main/res/BUCK @@ -36,4 +36,13 @@ rn_android_resource( ], ) +rn_android_resource( + name = "systeminfo", + package = "com.facebook.react", + res = "systeminfo", + visibility = [ + "PUBLIC", + ], +) + # New resource directories must be added to react-native-github/ReactAndroid/build.gradle diff --git a/ReactAndroid/src/main/res/systeminfo/values/values.xml b/ReactAndroid/src/main/res/systeminfo/values/values.xml new file mode 100644 index 00000000000000..7d52389be83dad --- /dev/null +++ b/ReactAndroid/src/main/res/systeminfo/values/values.xml @@ -0,0 +1,5 @@ + + + 8081 + @integer/react_native_dev_server_port + diff --git a/react.gradle b/react.gradle index 07fd9e3f2541be..9b45a8899c384e 100644 --- a/react.gradle +++ b/react.gradle @@ -15,6 +15,22 @@ def reactRoot = file(config.root ?: "../../") def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] def bundleConfig = config.bundleConfig ? "${reactRoot}/${config.bundleConfig}" : null ; +def reactNativeDevServerPort() { + def value = project.getProperties().get("reactNativeDevServerPort") + return value != null ? value : "8081" +} + +def reactNativeInspectorProxyPort() { + def value = project.getProperties().get("reactNativeInspectorProxyPort") + return value != null ? value : reactNativeDevServerPort() +} + +android { + buildTypes.all { + resValue "integer", "react_native_dev_server_port", reactNativeDevServerPort() + resValue "integer", "react_native_inspector_proxy_port", reactNativeInspectorProxyPort() + } +} afterEvaluate { def isAndroidLibrary = plugins.hasPlugin("com.android.library") From 7a2463e1f396ffcfbd86e68170f624d31a1be4e1 Mon Sep 17 00:00:00 2001 From: James Ide Date: Wed, 5 Jun 2019 10:51:51 -0700 Subject: [PATCH 103/330] Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper (#24811) Summary: **Depends on https://github.com/facebook/react-native/pull/25100** This commit depends on having migrated all of RN away from Haste. With 100% standard path-based requires, the key foundation is set and we no longer need `hasteImpl` and related settings in the Jest configuration. This commit deletes the `hasteImpl` file and setting as well as `providesModuleNodeModules` and `modulePathNameMapper`, removing most of the dependency graph overriding performed by Jest. ## Changelog [General] [Changed] - Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper from Jest config Pull Request resolved: https://github.com/facebook/react-native/pull/24811 Differential Revision: D15659274 Pulled By: cpojer fbshipit-source-id: 8a4a3b97ddf7e38fbe62c6d3cc9c98248bfca343 --- jest-preset.js | 8 --- jest.config.js | 38 ------------- jest/__tests__/hasteImpl-test.js | 93 -------------------------------- jest/hasteImpl.js | 85 +---------------------------- 4 files changed, 2 insertions(+), 222 deletions(-) delete mode 100644 jest/__tests__/hasteImpl-test.js diff --git a/jest-preset.js b/jest-preset.js index 3de412bebd571e..5a3051ff384b2f 100644 --- a/jest-preset.js +++ b/jest-preset.js @@ -9,19 +9,11 @@ 'use strict'; -const dir = __dirname; - module.exports = { haste: { defaultPlatform: 'ios', platforms: ['android', 'ios', 'native'], - hasteImplModulePath: require.resolve('./jest/hasteImpl.js'), - providesModuleNodeModules: ['react-native'], - }, - moduleNameMapper: { - '^React$': require.resolve('react'), }, - modulePathIgnorePatterns: [`${dir}/Libraries/react-native/`], transform: { '^.+\\.(js|ts|tsx)$': 'babel-jest', '^.+\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$': require.resolve( diff --git a/jest.config.js b/jest.config.js index 3ed6cd49c14fb6..a157f236941cf4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -17,9 +17,6 @@ module.exports = { './jest/setup.js', ], 'timers': 'fake', - 'moduleNameMapper': { - '^React$': '/Libraries/react-native/React.js', - }, 'testRegex': '/__tests__/.*-test\\.js$', 'testPathIgnorePatterns': [ '/node_modules/', @@ -29,46 +26,11 @@ module.exports = { ], 'haste': { 'defaultPlatform': 'ios', - 'hasteImplModulePath': '/jest/hasteImpl.js', - 'providesModuleNodeModules': [ - 'react-native', - ], 'platforms': [ 'ios', 'android', ], }, - 'modulePathIgnorePatterns': [ - '/node_modules/(?!react|fbjs|react-native|react-transform-hmr|core-js|promise)/', - 'node_modules/react/node_modules/fbjs/', - 'node_modules/react/lib/ReactDOM.js', - 'node_modules/fbjs/lib/Map.js', - 'node_modules/fbjs/lib/Promise.js', - 'node_modules/fbjs/lib/fetch.js', - 'node_modules/fbjs/lib/ErrorUtils.js', - 'node_modules/fbjs/lib/URI.js', - 'node_modules/fbjs/lib/Deferred.js', - 'node_modules/fbjs/lib/PromiseMap.js', - 'node_modules/fbjs/lib/UserAgent.js', - 'node_modules/fbjs/lib/areEqual.js', - 'node_modules/fbjs/lib/base62.js', - 'node_modules/fbjs/lib/crc32.js', - 'node_modules/fbjs/lib/everyObject.js', - 'node_modules/fbjs/lib/fetchWithRetries.js', - 'node_modules/fbjs/lib/filterObject.js', - 'node_modules/fbjs/lib/flattenArray.js', - 'node_modules/fbjs/lib/forEachObject.js', - 'node_modules/fbjs/lib/isEmpty.js', - 'node_modules/fbjs/lib/removeFromArray.js', - 'node_modules/fbjs/lib/resolveImmediate.js', - 'node_modules/fbjs/lib/someObject.js', - 'node_modules/fbjs/lib/sprintf.js', - 'node_modules/fbjs/lib/xhrSimpleDataSerializer.js', - 'node_modules/jest-cli', - 'node_modules/react/dist', - 'node_modules/fbjs/.*/__mocks__/', - 'node_modules/fbjs/node_modules/', - ], 'unmockedModulePathPatterns': [ 'node_modules/react/', 'Libraries/Renderer', diff --git a/jest/__tests__/hasteImpl-test.js b/jest/__tests__/hasteImpl-test.js deleted file mode 100644 index 9cab29a52215f8..00000000000000 --- a/jest/__tests__/hasteImpl-test.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+js_foundation - */ - -'use strict'; - -const path = require('path'); - -const {getHasteName} = require('../hasteImpl'); - -function getPath(...parts) { - return path.join(__dirname, '..', '..', ...parts); -} - -it('returns the correct haste name for a RN library file', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - 'AccessibilityInfo.js', - ), - ), - ).toEqual('AccessibilityInfo'); -}); - -it('returns the correct haste name for a file with a platform suffix', () => { - for (const platform of ['android', 'ios', 'native']) { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - `AccessibilityInfo.${platform}.js`, - ), - ), - ).toEqual('AccessibilityInfo'); - } -}); - -it('returns the correct haste name for a file with a flow suffix', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - 'AccessibilityInfo.ios.js.flow', - ), - ), - ).toEqual('AccessibilityInfo'); -}); - -it('does not calculate the haste name for a file that is not JS', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - 'AccessibilityInfo.txt', - ), - ), - ).toBe(undefined); -}); - -it('does not calculate the haste name for a file outside of RN', () => { - expect( - getHasteName(getPath('..', 'Libraries', 'AccessibilityInfo.txt')), - ).toBe(undefined); -}); - -it('does not calculate the haste name for a blacklisted file', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - '__mocks__', - 'AccessibilityInfo', - 'AccessibilityInfo.js', - ), - ), - ).toBe(undefined); -}); diff --git a/jest/hasteImpl.js b/jest/hasteImpl.js index eae413a937df2f..d1c1fad686ba5d 100644 --- a/jest/hasteImpl.js +++ b/jest/hasteImpl.js @@ -5,93 +5,12 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow */ 'use strict'; -const path = require('path'); -const cli = require('@react-native-community/cli'); - -// Use duck-typing because of Facebook-internal infra that doesn't have the cli package. -const {haste} = (cli.loadConfig && cli.loadConfig()) || { - haste: { - providesModuleNodeModules: [], - platforms: ['ios', 'android'], - }, -}; - -// Detect out-of-tree platforms and add them to the whitelists -const pluginRoots /*: Array */ = haste.providesModuleNodeModules.map( - name => path.resolve(__dirname, '../../', name) + path.sep, -); - -const pluginNameReducers /*: Array<[RegExp, string]> */ = haste.platforms.map( - name => [new RegExp(`^(.*)\\.(${name})$`), '$1'], -); - -const ROOTS = [path.resolve(__dirname, '..') + path.sep, ...pluginRoots]; - -const BLACKLISTED_PATTERNS /*: Array */ = [ - /.*[\\\/]__(mocks|tests)__[\\\/].*/, - /^Libraries[\\\/]Animated[\\\/]src[\\\/]polyfills[\\\/].*/, - /^Libraries[\\\/]Renderer[\\\/]fb[\\\/].*/, - /DerivedData[\\\/].*/, -]; - -const WHITELISTED_PREFIXES /*: Array */ = [ - 'IntegrationTests', - 'Libraries', - 'ReactAndroid', - 'RNTester', -]; - -const NAME_REDUCERS /*: Array<[RegExp, string]> */ = [ - // extract basename - [/^(?:.*[\\\/])?([a-zA-Z0-9$_.-]+)$/, '$1'], - // strip .js/.js.flow suffix - [/^(.*)\.js(\.flow)?$/, '$1'], - // strip native suffix - [/^(.*)\.(native)$/, '$1'], - // strip plugin platform suffixes - ...pluginNameReducers, -]; - -function isHastePath(filePath /*: string */) /*: boolean */ { - if (!filePath.endsWith('.js') && !filePath.endsWith('.js.flow')) { - return false; - } - - const root = ROOTS.find(r => filePath.startsWith(r)); - if (!root) { - return false; - } - - filePath = filePath.substr(root.length); - if (BLACKLISTED_PATTERNS.some(pattern => pattern.test(filePath))) { - return false; - } - return WHITELISTED_PREFIXES.some(prefix => filePath.startsWith(prefix)); -} - module.exports = { - /* - * @return {string|void} hasteName for module at filePath; or undefined if - * filePath is not a haste module - */ - getHasteName( - filePath /*: string */, - sourceCode /*: ?string */, - ) /*: string | void */ { - if (!isHastePath(filePath)) { - return undefined; - } - - const hasteName = NAME_REDUCERS.reduce( - (name, [pattern, replacement]) => name.replace(pattern, replacement), - filePath, - ); - - return hasteName; + getHasteName() { + return undefined; }, }; From c1e03b34dfe29b0ef9dc677b0c7c2c9ae399b782 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 5 Jun 2019 15:10:50 -0700 Subject: [PATCH 104/330] Sync commit from React Summary: This diff syncs a commit from React to bring in https://github.com/facebook/react/pull/15802#pullrequestreview-245969201 Reviewed By: cpojer Differential Revision: D15660020 fbshipit-source-id: 15d2413a69968b2898bb37d256f35bc09ebc8d58 --- .../implementations/ReactFabric-dev.fb.js | 4 +--- .../implementations/ReactFabric-dev.js | 4 +--- .../implementations/ReactFabric-prod.fb.js | 22 +++++++++---------- .../implementations/ReactFabric-prod.js | 22 +++++++++---------- .../ReactFabric-profiling.fb.js | 22 +++++++++---------- .../implementations/ReactFabric-profiling.js | 22 +++++++++---------- .../ReactNativeRenderer-dev.fb.js | 4 +--- .../ReactNativeRenderer-dev.js | 4 +--- .../ReactNativeRenderer-prod.fb.js | 22 +++++++++---------- .../ReactNativeRenderer-prod.js | 22 +++++++++---------- .../ReactNativeRenderer-profiling.fb.js | 22 +++++++++---------- .../ReactNativeRenderer-profiling.js | 22 +++++++++---------- .../shims/ReactNativeViewConfigRegistry.js | 7 ++---- 13 files changed, 86 insertions(+), 113 deletions(-) diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js index 01a54327173ccf..d2974a687cf44e 100644 --- a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -2461,11 +2461,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.js b/Libraries/Renderer/implementations/ReactFabric-dev.js index f1676471c4da4e..9d98a9b2c01198 100644 --- a/Libraries/Renderer/implementations/ReactFabric-dev.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.js @@ -2462,11 +2462,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js index 414151d1168e47..311927f216750e 100644 --- a/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +++ b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -946,10 +946,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -976,14 +981,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactFabric-prod.js b/Libraries/Renderer/implementations/ReactFabric-prod.js index 50abb2ccc511cd..a3f53b2478f817 100644 --- a/Libraries/Renderer/implementations/ReactFabric-prod.js +++ b/Libraries/Renderer/implementations/ReactFabric-prod.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js index 722fac68035257..86dc0c56155220 100644 --- a/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactFabric-profiling.js b/Libraries/Renderer/implementations/ReactFabric-profiling.js index 9cd8fe74bcf731..5f93b0a2a343a9 100644 --- a/Libraries/Renderer/implementations/ReactFabric-profiling.js +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.js @@ -948,10 +948,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -978,14 +983,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js index d6da48c340b9b9..dbc36332f0bbe5 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -2461,11 +2461,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js index 1566edf036983a..fa0c313a207946 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js @@ -2462,11 +2462,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js index a97536ba85c30c..172a8fa197f016 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -946,10 +946,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -976,14 +981,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js index 4e2b964402e434..131b6b97ef8086 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js index 656ffb77a84847..78400babb59af5 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js index 0df2e6154a6b70..c75d5a1e4dccf0 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js @@ -948,10 +948,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -978,14 +983,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index cb27a9d9668616..b39983d5e6062d 100644 --- a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -20,11 +20,9 @@ const invariant = require('invariant'); // Event configs const customBubblingEventTypes = {}; const customDirectEventTypes = {}; -const eventTypes = {}; exports.customBubblingEventTypes = customBubblingEventTypes; exports.customDirectEventTypes = customDirectEventTypes; -exports.eventTypes = eventTypes; const viewConfigCallbacks = new Map(); const viewConfigs = new Map(); @@ -49,7 +47,7 @@ function processEventTypes( if (bubblingEventTypes != null) { for (const topLevelType in bubblingEventTypes) { if (customBubblingEventTypes[topLevelType] == null) { - eventTypes[topLevelType] = customBubblingEventTypes[topLevelType] = + customBubblingEventTypes[topLevelType] = bubblingEventTypes[topLevelType]; } } @@ -58,8 +56,7 @@ function processEventTypes( if (directEventTypes != null) { for (const topLevelType in directEventTypes) { if (customDirectEventTypes[topLevelType] == null) { - eventTypes[topLevelType] = customDirectEventTypes[topLevelType] = - directEventTypes[topLevelType]; + customDirectEventTypes[topLevelType] = directEventTypes[topLevelType]; } } } From bf8d91868182955899edab3b0b91a0be53ce276d Mon Sep 17 00:00:00 2001 From: James Ide Date: Wed, 5 Jun 2019 15:57:36 -0700 Subject: [PATCH 105/330] Make Flow configs use path-based imports instead of Haste (#24812) Summary: **Depends on https://github.com/facebook/react-native/pull/25100** This is one of the steps unlocked by migrating RN from Haste to path-based imports. This commit sets Flow to use path-based imports by removing all of the Haste-related configuration options. Additionally, it maps `react-native` to import from within this module to match Node's module resolution behavior. It also adds `` to the image name mapper so that the mapped name doesn't rely on Haste. ## Changelog [General] [Changed] - Make Flow configs use path-based imports instead of Haste Pull Request resolved: https://github.com/facebook/react-native/pull/24812 Differential Revision: D15659189 Pulled By: cpojer fbshipit-source-id: d0efaa2884485a492dcdef8d94061129cebc2566 --- .flowconfig | 31 +++---------------------------- .flowconfig.android | 31 +++---------------------------- template/_flowconfig | 30 +++--------------------------- 3 files changed, 9 insertions(+), 83 deletions(-) diff --git a/.flowconfig b/.flowconfig index 2df42b89ca436c..0fa25e0ca34dd2 100644 --- a/.flowconfig +++ b/.flowconfig @@ -11,14 +11,6 @@ ; Ignore "BUCK" generated dirs /\.buckd/ -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -.*/Libraries/react-native/React.js - ; Ignore polyfills .*/Libraries/polyfills/.* @@ -48,28 +40,11 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.ios.js -module.system=haste -module.system.haste.use_name_reducers=true -# keep the following in sync with server/haste/hasteImpl.js -# get basename -module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' -# strip .js or .js.flow suffix -module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' -# strip .ios suffix -module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' -module.system.haste.paths.blacklist=.*/__tests__/.* -module.system.haste.paths.blacklist=.*/__mocks__/.* -module.system.haste.paths.whitelist=/Libraries/.* -module.system.haste.paths.whitelist=/RNTester/.* -module.system.haste.paths.whitelist=/IntegrationTests/.* -module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* - munge_underscores=true -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' +module.name_mapper='^react-native$' -> '/Libraries/react-native/react-native-implementation' +module.name_mapper='^react-native/\(.*\)$' -> '/\1' +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/Libraries/Image/RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe diff --git a/.flowconfig.android b/.flowconfig.android index 1d47c484efc3ca..97f4f99ad060db 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -11,14 +11,6 @@ ; Ignore "BUCK" generated dirs /\.buckd/ -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -.*/Libraries/react-native/React.js - ; Ignore polyfills .*/Libraries/polyfills/.* @@ -48,28 +40,11 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.android.js -module.system=haste -module.system.haste.use_name_reducers=true -# keep the following in sync with server/haste/hasteImpl.js -# get basename -module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' -# strip .js or .js.flow suffix -module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' -# strip .android suffix -module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' -module.system.haste.paths.blacklist=.*/__tests__/.* -module.system.haste.paths.blacklist=.*/__mocks__/.* -module.system.haste.paths.whitelist=/Libraries/.* -module.system.haste.paths.whitelist=/RNTester/.* -module.system.haste.paths.whitelist=/IntegrationTests/.* -module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* - munge_underscores=true -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' +module.name_mapper='^react-native$' -> '/Libraries/react-native/react-native-implementation' +module.name_mapper='^react-native/\(.*\)$' -> '/\1' +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/Libraries/Image/RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe diff --git a/template/_flowconfig b/template/_flowconfig index 80fa55fc38a41d..49091799f945e8 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -5,14 +5,6 @@ ; Ignore "BUCK" generated dirs /\.buckd/ -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -node_modules/react-native/Libraries/react-native/React.js - ; Ignore polyfills node_modules/react-native/Libraries/polyfills/.* @@ -42,27 +34,11 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.ios.js -module.system=haste -module.system.haste.use_name_reducers=true -# get basename -module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' -# strip .js or .js.flow suffix -module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' -# strip .ios suffix -module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' -module.system.haste.paths.blacklist=.*/__tests__/.* -module.system.haste.paths.blacklist=.*/__mocks__/.* -module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* -module.system.haste.paths.whitelist=/node_modules/react-native/RNTester/.* -module.system.haste.paths.whitelist=/node_modules/react-native/IntegrationTests/.* -module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* - munge_underscores=true -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' +module.name_mapper='^react-native$' -> '/Libraries/react-native/react-native-implementation' +module.name_mapper='^react-native/\(.*\)$' -> '/\1' +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/Libraries/Image/RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe From d45818fe47c53a670db933cf805910e227aa79c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Borowy Date: Wed, 5 Jun 2019 15:59:46 -0700 Subject: [PATCH 106/330] Feature to listen on window focus events (#25039) Summary: Addressed issue: https://github.com/facebook/react-native/issues/24149 On Android, activity's lifecycle events are not triggered when the user pulls down the Status Bar (opening Notification Drawer). In order to know that, you need to override [onWindowFocusChanged method](https://developer.android.com/reference/android/app/Activity.html#onWindowFocusChanged(boolean)). ## Changelog [Android] [Added] - Adds a new listener for `onWindowFocusChanged` [JavaScript] [Added] - New event, `focusChanged`, to listen on focus gain/loss Pull Request resolved: https://github.com/facebook/react-native/pull/25039 Differential Revision: D15644954 Pulled By: cpojer fbshipit-source-id: 823acffc4287bec4bf56e9f5ffcac65c01cf13d3 --- Libraries/AppState/AppState.js | 58 +++++++++++++------ .../com/facebook/react/ReactActivity.java | 6 ++ .../facebook/react/ReactActivityDelegate.java | 6 ++ .../facebook/react/ReactInstanceManager.java | 9 +++ .../facebook/react/bridge/ReactContext.java | 21 +++++++ .../bridge/WindowFocusChangeListener.java | 15 +++++ .../modules/appstate/AppStateModule.java | 10 +++- 7 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index 24b7da77d01481..e848978a106894 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -25,6 +25,7 @@ const invariant = require('invariant'); */ class AppState extends NativeEventEmitter { _eventHandlers: Object; + _supportedEvents = ['change', 'memoryWarning', 'blur', 'focus']; currentState: ?string; isAvailable: boolean; @@ -32,10 +33,10 @@ class AppState extends NativeEventEmitter { super(NativeAppState); this.isAvailable = true; - this._eventHandlers = { - change: new Map(), - memoryWarning: new Map(), - }; + this._eventHandlers = this._supportedEvents.reduce((handlers, key) => { + handlers[key] = new Map(); + return handlers; + }, {}); this.currentState = NativeAppState.getConstants().initialAppState; @@ -75,22 +76,43 @@ class AppState extends NativeEventEmitter { */ addEventListener(type: string, handler: Function) { invariant( - ['change', 'memoryWarning'].indexOf(type) !== -1, + this._supportedEvents.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type, ); - if (type === 'change') { - this._eventHandlers[type].set( - handler, - this.addListener('appStateDidChange', appStateData => { - handler(appStateData.app_state); - }), - ); - } else if (type === 'memoryWarning') { - this._eventHandlers[type].set( - handler, - this.addListener('memoryWarning', handler), - ); + + switch (type) { + case 'change': { + this._eventHandlers[type].set( + handler, + this.addListener('appStateDidChange', appStateData => { + handler(appStateData.app_state); + }), + ); + break; + } + case 'memoryWarning': { + this._eventHandlers[type].set( + handler, + this.addListener('memoryWarning', handler), + ); + break; + } + + case 'blur': + case 'focus': { + this._eventHandlers[type].set( + handler, + this.addListener('appStateFocusChange', hasFocus => { + if (type === 'blur' && !hasFocus) { + handler(); + } + if (type === 'focus' && hasFocus) { + handler(); + } + }), + ); + } } } @@ -101,7 +123,7 @@ class AppState extends NativeEventEmitter { */ removeEventListener(type: string, handler: Function) { invariant( - ['change', 'memoryWarning'].indexOf(type) !== -1, + this._supportedEvents.indexOf(type) !== -1, 'Trying to remove listener for unknown event: "%s"', type, ); diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java index 080fb54e083df4..1dd6d18073c2e8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java @@ -125,6 +125,12 @@ public void onRequestPermissionsResult( mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + mDelegate.onWindowFocusChanged(hasFocus); + } + protected final ReactNativeHost getReactNativeHost() { return mDelegate.getReactNativeHost(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java index 26a95665654d32..c6534217a084e3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java @@ -182,6 +182,12 @@ public boolean onNewIntent(Intent intent) { return false; } + public void onWindowFocusChanged(boolean hasFocus) { + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onWindowFocusChange(hasFocus); + } + } + @TargetApi(Build.VERSION_CODES.M) public void requestPermissions( String[] permissions, diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 0926cf7efb37ce..1247027e29ad1e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -703,6 +703,15 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, } } + @ThreadConfined(UI) + public void onWindowFocusChange(boolean hasFocus) { + UiThreadUtil.assertOnUiThread(); + ReactContext currentContext = getCurrentReactContext(); + if (currentContext != null) { + currentContext.onWindowFocusChange(hasFocus); + } + } + @ThreadConfined(UI) public void showDevOptionsDialog() { UiThreadUtil.assertOnUiThread(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java index 532c226324a9d0..c2e74c0b89726d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java @@ -36,6 +36,8 @@ public class ReactContext extends ContextWrapper { new CopyOnWriteArraySet<>(); private final CopyOnWriteArraySet mActivityEventListeners = new CopyOnWriteArraySet<>(); + private final CopyOnWriteArraySet mWindowFocusEventListeners = + new CopyOnWriteArraySet<>(); private LifecycleState mLifecycleState = LifecycleState.BEFORE_CREATE; @@ -196,6 +198,14 @@ public void removeActivityEventListener(ActivityEventListener listener) { mActivityEventListeners.remove(listener); } + public void addWindowFocusChangeListener(WindowFocusChangeListener listener) { + mWindowFocusEventListeners.add(listener); + } + + public void removeWindowFocusChangeListener(WindowFocusChangeListener listener) { + mWindowFocusEventListeners.remove(listener); + } + /** * Should be called by the hosting Fragment in {@link Fragment#onResume} */ @@ -281,6 +291,17 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, } } + public void onWindowFocusChange(boolean hasFocus) { + UiThreadUtil.assertOnUiThread(); + for (WindowFocusChangeListener listener : mWindowFocusEventListeners) { + try { + listener.onWindowFocusChange(hasFocus); + } catch (RuntimeException e) { + handleException(e); + } + } + } + public void assertOnUiQueueThread() { Assertions.assertNotNull(mUiMessageQueueThread).assertIsOnThread(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java new file mode 100644 index 00000000000000..d74b1089f9a0c1 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java @@ -0,0 +1,15 @@ +// Copyright (c) Facebook, Inc. and its affiliates. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + + +package com.facebook.react.bridge; + + +/* + * Listener for receiving window focus events. + */ +public interface WindowFocusChangeListener { + void onWindowFocusChange(boolean hasFocus); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java index ee158be0f40fcb..6dc073cd275d54 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java @@ -13,6 +13,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WindowFocusChangeListener; import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.LifecycleState; import com.facebook.react.module.annotations.ReactModule; @@ -23,7 +24,7 @@ @ReactModule(name = AppStateModule.NAME) public class AppStateModule extends ReactContextBaseJavaModule - implements LifecycleEventListener { + implements LifecycleEventListener, WindowFocusChangeListener { protected static final String NAME = "AppState"; @@ -37,6 +38,7 @@ public class AppStateModule extends ReactContextBaseJavaModule public AppStateModule(ReactApplicationContext reactContext) { super(reactContext); reactContext.addLifecycleEventListener(this); + reactContext.addWindowFocusChangeListener(this); mAppState = (reactContext.getLifecycleState() == LifecycleState.RESUMED ? APP_STATE_ACTIVE : APP_STATE_BACKGROUND); } @@ -76,6 +78,12 @@ public void onHostDestroy() { // catalyst instance is going to be immediately dropped, and all JS calls with it. } + @Override + public void onWindowFocusChange(boolean hasFocus) { + getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class) + .emit("appStateFocusChange", hasFocus); + } + private WritableMap createAppStateEventMap() { WritableMap appState = Arguments.createMap(); appState.putString("app_state", mAppState); From 8a014cdfb3f33a7b49a68205e72c609c9ff3bb62 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 5 Jun 2019 17:30:04 -0700 Subject: [PATCH 107/330] TurboModules: Improve Error Message Summary: More verbose but descriptive error message when `TurboModule.getEnforcing` fails to find a native module. Reviewed By: cpojer, gaearon Differential Revision: D15619293 fbshipit-source-id: 0e8af4986d6ce9002966bb062766218ce9f89a13 --- Libraries/TurboModule/TurboModuleRegistry.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Libraries/TurboModule/TurboModuleRegistry.js b/Libraries/TurboModule/TurboModuleRegistry.js index fcec0d8ada5eda..d0e0cd0176c33a 100644 --- a/Libraries/TurboModule/TurboModuleRegistry.js +++ b/Libraries/TurboModule/TurboModuleRegistry.js @@ -33,6 +33,10 @@ export function get(name: string): ?T { export function getEnforcing(name: string): T { const module = get(name); - invariant(module != null, `${name} is not available in this app.`); + invariant( + module != null, + `TurboModuleRegistry.getEnforcing(...): '${name}' could not be found. ` + + 'Verify that a module by this name is registered in the native binary.', + ); return module; } From 664646055a3eee2a6ad031294eac4b2ec18a2cf4 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 5 Jun 2019 18:55:34 -0700 Subject: [PATCH 108/330] RN: Restore Debug Bridge Description (iOS) Summary: Restores the bridge description in the debug menu on iOS. Reviewed By: fkgozali Differential Revision: D15680775 fbshipit-source-id: c17ad44f2287e03bb2039b4aa4b1311e7ec9106b --- React/CxxBridge/RCTCxxBridge.mm | 4 +--- React/DevSupport/RCTDevMenu.m | 9 +++++++-- ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index 5a7188b5030761..93eac488eab00c 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -80,9 +80,7 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) { std::shared_ptr delegate, std::shared_ptr jsQueue) override { auto ret = factory_->createJSExecutor(delegate, jsQueue); - bridge_.bridgeDescription = - [NSString stringWithFormat:@"RCTCxxBridge %s", - ret->getDescription().c_str()]; + bridge_.bridgeDescription = @(ret->getDescription().c_str()); return ret; } diff --git a/React/DevSupport/RCTDevMenu.m b/React/DevSupport/RCTDevMenu.m index a57c4222cfdde0..80ad94cbf387b6 100644 --- a/React/DevSupport/RCTDevMenu.m +++ b/React/DevSupport/RCTDevMenu.m @@ -354,10 +354,15 @@ - (void)setDefaultJSBundle { return; } + NSString *bridgeDescription = _bridge.bridgeDescription; + NSString *description = bridgeDescription.length > 0 + ? [NSString stringWithFormat:@"Running %@", bridgeDescription] + : nil; + // On larger devices we don't have an anchor point for the action sheet UIAlertControllerStyle style = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? UIAlertControllerStyleActionSheet : UIAlertControllerStyleAlert; - _actionSheet = [UIAlertController alertControllerWithTitle:nil - message:nil + _actionSheet = [UIAlertController alertControllerWithTitle:@"React Native Debug Menu" + message:description preferredStyle:style]; NSArray *items = [self _menuItemsToPresent]; diff --git a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp index e7ec74077fda82..351d26fe06714b 100644 --- a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp +++ b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp @@ -241,7 +241,7 @@ void JSIExecutor::setGlobalVariable( } std::string JSIExecutor::getDescription() { - return "JSI " + runtime_->description(); + return "JSI (" + runtime_->description() + ")"; } void *JSIExecutor::getJavaScriptContext() { From 764fd955db7150313c51dd3303e30ed8e7f14772 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 5 Jun 2019 18:58:38 -0700 Subject: [PATCH 109/330] Setup TurboModuleManager inside Fb4a Summary: This diff introduces `TurboModuleManagerDelegate` in Fb4a and Workplace. `Fb4aTurboModuleManagerDelegate` is responsible for creating TurboModules for Fb4a. `WorkTurboModuleManagerDelegate` is responsible for creating TurboModules for Workplace. Reviewed By: mdvacca Differential Revision: D15268563 fbshipit-source-id: c254c31856c59b3551bfe54b25c715c848646c5a --- ...eactPackageTurboModuleManagerDelegate.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java index 839ada2cf080bc..4f5ba651247be2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java @@ -2,6 +2,7 @@ package com.facebook.react.turbomodule.core; +import com.facebook.infer.annotation.Assertions; import com.facebook.react.ReactPackage; import com.facebook.react.TurboReactPackage; import com.facebook.react.bridge.CxxModuleWrapper; @@ -19,7 +20,7 @@ public abstract class ReactPackageTurboModuleManagerDelegate extends TurboModule private final Map mModules = new HashMap<>(); private final ReactApplicationContext mReactApplicationContext; - public ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { + protected ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { super(); mReactApplicationContext = reactApplicationContext; for (ReactPackage reactPackage : packages) { @@ -101,4 +102,27 @@ private TurboModule resolveModule(String moduleName) { return mModules.get(moduleName); } + + public static abstract class Builder { + private @Nullable List mPackages; + private @Nullable ReactApplicationContext mContext; + + public Builder setPackages(List packages) { + mPackages = new ArrayList<>(packages); + return this; + } + + public Builder setReactApplicationContext(ReactApplicationContext context) { + mContext = context; + return this; + } + + protected abstract ReactPackageTurboModuleManagerDelegate build(ReactApplicationContext context, List packages); + + public ReactPackageTurboModuleManagerDelegate build() { + Assertions.assertNotNull(mContext, "The ReactApplicationContext must be provided to create ReactPackageTurboModuleManagerDelegate"); + Assertions.assertNotNull(mPackages, "A set of ReactPackages must be provided to create ReactPackageTurboModuleManagerDelegate"); + return build(mContext, mPackages); + } + } } From 7b9c456e7d9299e908aa1bdeff0c3f8ab5bd5f01 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 5 Jun 2019 18:58:38 -0700 Subject: [PATCH 110/330] Enable TurboModules for FB4A Summary: ## Summary If a NativeModule Spec interface extends `TurboModule`, we want to make the auto-generated Java base class for that NativeModule to implement `com.facebook.react.turbomodule.core.interfaces.TurboModule`. This makes it so that our Android code recognizes that Java module as a TurboModule. When this diff lands, all internal FB4A NativeModules will start going through the TurboModule system. Reviewed By: fkgozali Differential Revision: D15327683 fbshipit-source-id: e295dafdab7a0e130820318aeaf0cafa41487689 --- .../main/java/com/facebook/react/bridge/BaseJavaModule.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index 04ca7a91c74969..da1d60f94f0897 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -67,4 +67,9 @@ public void onCatalystInstanceDestroy() { public boolean hasConstants() { return false; } + + // Cleanup Logic for TurboModuels + public void invalidate() { + // Do nothing + } } From 9fdc8daf6152382e787b5da175722435c28bf8b9 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 5 Jun 2019 18:58:38 -0700 Subject: [PATCH 111/330] Fix race in TurboModuleManager initialization Summary: ## Description To initialize `TurboModuleManager`, we first need to wait until `ReactContext` is initialized. Then, we get the `TurboModuleManager` instance and assign it as the `TurboModuleRegistry` of `CatalystInstanceImpl`. This allows `CatalystInstanceImpl` to return TurboModules from its `getNativeModule` method. In `FbReactFragment`, we also wait until the `ReactContext` is initialized before then eagerly initialize a bunch of NativeModules. All this waiting is done by adding instances of `ReactInstanceEventListener` to `ReactInstanceManager`'s `mReactInstanceEventListeners` synchronized Set. When the `ReactContext` is finally initialized, we loop over this set and invoke all the listeners. ## Problem We want to initialize `TurboModuleManager` and set it as the `TurboModuleRegistry` of `CatalystInstanceImpl` before we start eagerly initializing our NativeModules. Why? Because otherwise TurboModules that need to be eagerly initialized won't be. The fact that we're using a Set to manage the `ReactInstanceEventListener`s means that our listeners can be invoked in any order. This is bad because we can start to eagerly initialize NativeModules before we've had the chance to assign `TurboModuleManager` as the `TurboModuleRegistry` of `CatalystInstanceImpl`. In development, this race was leading to the following crash: ``` 06-05 11:11:02.020 10461 10617 E AndroidRuntime: FATAL EXCEPTION: CombinedTP8 06-05 11:11:02.020 10461 10617 E AndroidRuntime: Process: com.facebook.wakizashi, PID: 10461 06-05 11:11:02.020 10461 10617 E AndroidRuntime: java.lang.AssertionError: Could not find module with name PrimedStorage 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.infer.annotation.Assertions.assertNotNull(Assertions.java:35) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:147) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:444) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.fbreact.fragment.FbReactFragment$4$1.run(FbReactFragment.java:418) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.WrappingExecutorService$1.run(WrappingExecutorService.java:82) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedSimpleTask.run(CombinedSimpleTask.java:81) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedLifetimeThreadFactory$1.run(CombinedLifetimeThreadFactory.java:40) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.NamedThreadFactory$1.run(NamedThreadFactory.java:53) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764) ``` ## Diagnosing the crash It looks like `NativeModuleRegistry.getModule` was throwing an error because `PrimedStorage` was null. `PrimedStorage` was turned into a TurboModule, so of course it wouldn't be in the `NativeModuleRegistry`. It should be in the `TurboModuleRegistry`. So, I placed an assertion in `CatalystInstanceImpl`: ``` Override public NativeModule getNativeModule(String moduleName) { Assertions.assertNotNull(mTurboModuleRegistry, "TurboModuleRegsitry is not null"); if (mTurboModuleRegistry != null) { TurboModule turboModule = mTurboModuleRegistry.getModule(moduleName); if (turboModule != null) { return (NativeModule)turboModule; } } return mNativeModuleRegistry.getModule(moduleName); } ``` Sure enough, this assertion started tripping, which meant that `mTurboModuleRegistry` was null. From this information, I hypothesized that we started to eagerly initialize our NativeModules before `TurboModuleManager` was initialized. To verify this hypothesis, I added logging statements in each `ReactInstanceEventListener`: P65477469. `eagerInitializeReactNativeComponents (START)` documents when we start to eagerly intialize our NativeModules. `getReactInstanceManager (START)` documents when we start to initialize `TurboModuleManager` inside `FbReactInstanceHolder.getReactInstanceManager` method. Sure enough, when the program finally crashed, I saw in our logs that we started eagerly initializing our NativeModules before we initialized the TurboModuleManager: ``` 06-05 11:11:01.951 10461 10617 V Ramanpreet: eagerInitializeReactNativeComponents (START): 1559758261951 06-05 11:11:01.956 10461 10461 V Ramanpreet: getReactInstanceManager (START): 1559758261956 06-05 11:11:01.958 10461 10461 D SoLoader: About to load: libturbomodulejsijni.so 06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-zstd 06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-xzs 06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-assets 06-05 11:11:01.961 10461 10461 D SoLoader: libturbomodulejsijni.so found on /data/data/com.facebook.wakizashi/lib-main 06-05 11:11:01.965 10461 10461 D SoLoader: Loading lib dependencies: [libfb.so, libfbjni.so, libglog.so, libdouble-conversion.so, libxplat_jsi_jsiAndroid.so, libxplat_jsi_JSIDynamicAndroid.so, libfbsystrace.so, libmemalign16.so, libgnustl_shared.so, libm.so, libc.so] 06-05 11:11:01.999 10461 10769 D SoLoader: init exiting 06-05 11:11:01.999 10461 10461 D SoLoader: Loaded: libturbomodulejsijni.so 06-05 11:11:01.999 10461 10461 D SoLoader: About to load: libfb4aturbomodulemanagerdelegate.so 06-05 11:11:01.999 10461 10769 W fb4a.ImagePipelineFactory: ImagePipelineFactory has already been initialized! `ImagePipelineFactory.initialize(...)` should only be called once to avoid unexpected behavior. 06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-zstd 06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-xzs 06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-assets 06-05 11:11:02.004 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so found on /data/data/com.facebook.wakizashi/lib-main 06-05 11:11:02.007 10461 10461 D SoLoader: Loading lib dependencies: [libturbomodulejsijni.so, libfb.so, libfbjni.so, libxplat_jsi_jsiAndroid.so, libxplat_jsi_JSIDynamicAndroid.so, libreactnativejni.so, libmemalign16.so, libgnustl_shared.so, libc.so] 06-05 11:11:02.020 10461 10617 E AndroidRuntime: FATAL EXCEPTION: CombinedTP8 06-05 11:11:02.020 10461 10617 E AndroidRuntime: Process: com.facebook.wakizashi, PID: 10461 06-05 11:11:02.020 10461 10617 E AndroidRuntime: java.lang.AssertionError: Could not find module with name PrimedStorage 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.infer.annotation.Assertions.assertNotNull(Assertions.java:35) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:147) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:444) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.fbreact.fragment.FbReactFragment$4$1.run(FbReactFragment.java:418) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.WrappingExecutorService$1.run(WrappingExecutorService.java:82) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedSimpleTask.run(CombinedSimpleTask.java:81) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedLifetimeThreadFactory$1.run(CombinedLifetimeThreadFactory.java:40) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.NamedThreadFactory$1.run(NamedThreadFactory.java:53) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764) 06-05 11:11:02.038 1647 1667 I WifiService: requestActivityInfo uid=1000 06-05 11:11:02.038 1647 1667 I WifiService: reportActivityInfo uid=1000 06-05 11:11:02.038 1647 1667 I WifiService: getSupportedFeatures uid=1000 06-05 11:11:02.044 1647 1667 E BluetoothAdapter: Bluetooth binder is null 06-05 11:11:02.049 1647 1667 E KernelCpuSpeedReader: Failed to read cpu-freq: /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state (No such file or directory) 06-05 11:11:02.050 1647 1667 E BatteryExternalStatsWorker: modem info is invalid: ModemActivityInfo{ mTimestamp=0 mSleepTimeMs=0 mIdleTimeMs=0 mTxTimeMs[]=[0, 0, 0, 0, 0] mRxTimeMs=0 mEnergyUsed=0} 06-05 11:11:02.057 2147 10435 W ctxmgr : [AclManager]No 2 for (accnt=account#-517948760#, com.google.android.gms(10013):IndoorOutdoorProducer, vrsn=13280000, 0, 3pPkg = null , 3pMdlId = null , pid = 2147). Was: 3 for 57, account#-517948760# 06-05 11:11:02.077 10461 10461 D SoLoader: Loaded: libfb4aturbomodulemanagerdelegate.so 06-05 11:11:02.079 10461 10461 V Ramanpreet: getReactInstanceManager (END): 1559758262079 ``` Reviewed By: mdvacca Differential Revision: D15676746 fbshipit-source-id: a7ac02d868abf31c5d664b10f70b6db247f388f5 --- .../src/main/java/com/facebook/react/ReactInstanceManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 1247027e29ad1e..f7f46ee13e88e1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -158,7 +158,7 @@ public interface ReactInstanceEventListener { private @Nullable @ThreadConfined(UI) DefaultHardwareBackBtnHandler mDefaultBackButtonImpl; private @Nullable Activity mCurrentActivity; private final Collection mReactInstanceEventListeners = - Collections.synchronizedSet(new HashSet()); + Collections.synchronizedList(new ArrayList()); // Identifies whether the instance manager is or soon will be initialized (on background thread) private volatile boolean mHasStartedCreatingInitialContext = false; // Identifies whether the instance manager destroy function is in process, From 7c2433c6d938c7a8fdfb55709473242d03272b9c Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Wed, 5 Jun 2019 21:32:15 -0700 Subject: [PATCH 112/330] DeviceInfo TurboModule Summary: Making DeviceInfo support TurboModule on Android; implementing the interface in the Java class and setting up codegen for the spec. Reviewed By: mdvacca Differential Revision: D15616194 fbshipit-source-id: 6326f23d95295e570df6f6c88289102ac733def7 --- ReactAndroid/src/main/java/com/facebook/react/BUCK | 1 + .../main/java/com/facebook/react/modules/deviceinfo/BUCK | 1 + .../facebook/react/modules/deviceinfo/DeviceInfoModule.java | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/BUCK b/ReactAndroid/src/main/java/com/facebook/react/BUCK index 2f9fa2dd606083..f5f371753deb76 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/BUCK @@ -44,6 +44,7 @@ rn_android_library( react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/views/imagehelper:imagehelper"), react_native_target("java/com/facebook/react/config:config"), + react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), ], exported_deps = [ react_native_target("java/com/facebook/react/packagerconnection:packagerconnection"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK index 76ee3429914464..e44249ce319b86 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK @@ -12,6 +12,7 @@ rn_android_library( react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), react_native_target("java/com/facebook/react/uimanager:uimanager"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java index eb792e8c16e81c..97629bf9048034 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java @@ -19,6 +19,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; import com.facebook.react.uimanager.DisplayMetricsHolder; /** @@ -26,7 +27,7 @@ */ @ReactModule(name = DeviceInfoModule.NAME) public class DeviceInfoModule extends BaseJavaModule implements - LifecycleEventListener { + LifecycleEventListener, TurboModule { public static final String NAME = "DeviceInfo"; @@ -89,4 +90,7 @@ public void emitUpdateDimensionsEvent() { .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("didUpdateDimensions", DisplayMetricsHolder.getDisplayMetricsNativeMap(mFontScale)); } + + @Override + public void invalidate() {} } From 56751851dfefd4b99d7cf478e6d04d9dc1aa4d11 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Wed, 5 Jun 2019 21:32:15 -0700 Subject: [PATCH 113/330] TurboModule for PlatformConstants Summary: Adding TurboModule for PlatformConstantsAndroid, and adding to Catalyst and Venice Reviewed By: mdvacca Differential Revision: D15630344 fbshipit-source-id: df6d5868cd3c9f54297bfea58683c8c1fd9375f0 --- .../react/modules/systeminfo/AndroidInfoModule.java | 6 +++++- .../main/java/com/facebook/react/modules/systeminfo/BUCK | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java index cf5ca4036c5597..6e2d61a3f34dc3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java @@ -21,6 +21,7 @@ import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; import java.util.HashMap; import java.util.Map; @@ -34,7 +35,7 @@ */ @ReactModule(name = AndroidInfoModule.NAME) @SuppressLint("HardwareIds") -public class AndroidInfoModule extends ReactContextBaseJavaModule { +public class AndroidInfoModule extends ReactContextBaseJavaModule implements TurboModule { public static final String NAME = "PlatformConstants"; private static final String IS_TESTING = "IS_TESTING"; @@ -89,6 +90,9 @@ public String getAndroidID(){ return Secure.getString(getReactApplicationContext().getContentResolver(),Secure.ANDROID_ID); } + @Override + public void invalidate() {} + private Boolean isRunningScreenshotTest() { try { Class.forName("android.support.test.rule.ActivityTestRule"); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK index 433ecaf80863a3..934de8ce65990d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK @@ -15,6 +15,7 @@ rn_android_library( react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("res:systeminfo"), + react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), ], exported_deps = [ ":systeminfo-moduleless", From cbbbb455dda313cca1a1763cc5453079ce87bc73 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 6 Jun 2019 02:40:34 -0700 Subject: [PATCH 114/330] Move ToolbarAndroid Java code to FB internal Summary: This moves the Toolbar Java files out RN and into our internal React shell. Reviewed By: fkgozali Differential Revision: D15469205 fbshipit-source-id: 15298505d74260618eb89673deb12d1b837b559f --- .../main/java/com/facebook/react/shell/BUCK | 1 - .../react/shell/MainReactPackage.java | 2 - .../com/facebook/react/views/toolbar/BUCK | 30 -- .../toolbar/DrawableWithIntrinsicSize.java | 47 --- .../react/views/toolbar/ReactToolbar.java | 332 ------------------ .../views/toolbar/ReactToolbarManager.java | 267 -------------- .../toolbar/events/ToolbarClickEvent.java | 49 --- 7 files changed, 728 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index e97f9ae9547134..fc134a5af2d35d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -63,7 +63,6 @@ rn_android_library( react_native_target("java/com/facebook/react/views/text:text"), react_native_target("java/com/facebook/react/views/text/frescosupport:frescosupport"), react_native_target("java/com/facebook/react/views/textinput:textinput"), - react_native_target("java/com/facebook/react/views/toolbar:toolbar"), react_native_target("java/com/facebook/react/views/view:view"), react_native_target("java/com/facebook/react/views/viewpager:viewpager"), react_native_target("java/com/facebook/react/module/annotations:annotations"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index 22348ac1dc63c0..3d1c17ae4dce3a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -59,7 +59,6 @@ import com.facebook.react.views.text.ReactVirtualTextViewManager; import com.facebook.react.views.text.frescosupport.FrescoBasedReactTextInlineImageViewManager; import com.facebook.react.views.textinput.ReactTextInputManager; -import com.facebook.react.views.toolbar.ReactToolbarManager; import com.facebook.react.views.view.ReactViewManager; import com.facebook.react.views.viewpager.ReactViewPagerManager; import java.util.ArrayList; @@ -335,7 +334,6 @@ public List createViewManagers(ReactApplicationContext reactContext viewManagers.add(new ReactScrollViewManager()); viewManagers.add(new ReactSliderManager()); viewManagers.add(new ReactSwitchManager()); - viewManagers.add(new ReactToolbarManager()); viewManagers.add(new SwipeRefreshLayoutManager()); // Native equivalents diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK deleted file mode 100644 index 55d7e0c8ed878c..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK +++ /dev/null @@ -1,30 +0,0 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "rn_android_library") - -rn_android_library( - name = "toolbar", - srcs = glob(["**/*.java"]), - is_androidx = True, - provided_deps = [ - react_native_dep("third-party/android/androidx:annotation"), - react_native_dep("third-party/android/androidx:appcompat"), - react_native_dep("third-party/android/androidx:core"), - react_native_dep("third-party/android/androidx:fragment"), - react_native_dep("third-party/android/androidx:legacy-support-core-ui"), - react_native_dep("third-party/android/androidx:legacy-support-core-utils"), - ], - visibility = [ - "PUBLIC", - ], - deps = [ - YOGA_TARGET, - react_native_dep("libraries/fresco/fresco-react-native:fbcore"), - react_native_dep("libraries/fresco/fresco-react-native:fresco-drawee"), - react_native_dep("libraries/fresco/fresco-react-native:fresco-react-native"), - react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/uimanager:uimanager"), - react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), - ], -) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java deleted file mode 100644 index b673abd96049ba..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.views.toolbar; - -import android.graphics.drawable.Drawable; - -import com.facebook.drawee.drawable.ForwardingDrawable; -import com.facebook.imagepipeline.image.ImageInfo; -import com.facebook.react.uimanager.PixelUtil; - -/** - * Fresco currently sets drawables' intrinsic size to (-1, -1). This is to guarantee that scaling is - * performed correctly. In the case of the Toolbar, we don't have access to the widget's internal - * ImageView, which has width/height set to WRAP_CONTENT, which relies on intrinsic size. - * - * To work around this we have this class which just wraps another Drawable, but returns the correct - * dimensions in getIntrinsicWidth/Height. This makes WRAP_CONTENT work in Toolbar's internals. - * - * This drawable uses the size of a loaded image to determine the intrinsic size. It therefore can't - * be used safely until *after* an image has loaded, and must be replaced when the image is - * replaced. - */ -public class DrawableWithIntrinsicSize extends ForwardingDrawable implements Drawable.Callback { - - private final ImageInfo mImageInfo; - - public DrawableWithIntrinsicSize(Drawable drawable, ImageInfo imageInfo) { - super(drawable); - mImageInfo = imageInfo; - } - - @Override - public int getIntrinsicWidth() { - return mImageInfo.getWidth(); - } - - @Override - public int getIntrinsicHeight() { - return mImageInfo.getHeight(); - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java deleted file mode 100644 index aca9653bb6702e..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java +++ /dev/null @@ -1,332 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.views.toolbar; - -import android.content.Context; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import androidx.appcompat.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; - -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.drawee.controller.BaseControllerListener; -import com.facebook.drawee.drawable.ScalingUtils; -import com.facebook.drawee.generic.GenericDraweeHierarchy; -import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; -import com.facebook.drawee.interfaces.DraweeController; -import com.facebook.drawee.view.DraweeHolder; -import com.facebook.drawee.view.MultiDraweeHolder; -import com.facebook.imagepipeline.image.ImageInfo; -import com.facebook.imagepipeline.image.QualityInfo; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.uimanager.PixelUtil; - -import javax.annotation.Nullable; - -/** - * Custom implementation of the {@link Toolbar} widget that adds support for remote images in logo - * and navigationIcon using fresco. - */ -public class ReactToolbar extends Toolbar { - - private static final String PROP_ACTION_ICON = "icon"; - private static final String PROP_ACTION_SHOW = "show"; - private static final String PROP_ACTION_SHOW_WITH_TEXT = "showWithText"; - private static final String PROP_ACTION_TITLE = "title"; - - private static final String PROP_ICON_URI = "uri"; - private static final String PROP_ICON_WIDTH = "width"; - private static final String PROP_ICON_HEIGHT = "height"; - - private final DraweeHolder mLogoHolder; - private final DraweeHolder mNavIconHolder; - private final DraweeHolder mOverflowIconHolder; - private final MultiDraweeHolder mActionsHolder = - new MultiDraweeHolder<>(); - - private IconControllerListener mLogoControllerListener; - private IconControllerListener mNavIconControllerListener; - private IconControllerListener mOverflowIconControllerListener; - - /** - * Attaches specific icon width & height to a BaseControllerListener which will be used to - * create the Drawable - */ - private abstract class IconControllerListener extends BaseControllerListener { - - private final DraweeHolder mHolder; - - private IconImageInfo mIconImageInfo; - - public IconControllerListener(DraweeHolder holder) { - mHolder = holder; - } - - public void setIconImageInfo(IconImageInfo iconImageInfo) { - mIconImageInfo = iconImageInfo; - } - - @Override - public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) { - super.onFinalImageSet(id, imageInfo, animatable); - - final ImageInfo info = mIconImageInfo != null ? mIconImageInfo : imageInfo; - setDrawable(new DrawableWithIntrinsicSize(mHolder.getTopLevelDrawable(), info)); - } - - protected abstract void setDrawable(Drawable d); - - } - - private class ActionIconControllerListener extends IconControllerListener { - private final MenuItem mItem; - - ActionIconControllerListener(MenuItem item, DraweeHolder holder) { - super(holder); - mItem = item; - } - - @Override - protected void setDrawable(Drawable d) { - mItem.setIcon(d); - ReactToolbar.this.requestLayout(); - } - } - - /** - * Simple implementation of ImageInfo, only providing width & height - */ - private static class IconImageInfo implements ImageInfo { - - private int mWidth; - private int mHeight; - - public IconImageInfo(int width, int height) { - mWidth = width; - mHeight = height; - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - @Override - public QualityInfo getQualityInfo() { - return null; - } - - } - - public ReactToolbar(Context context) { - super(context); - - mLogoHolder = DraweeHolder.create(createDraweeHierarchy(), context); - mNavIconHolder = DraweeHolder.create(createDraweeHierarchy(), context); - mOverflowIconHolder = DraweeHolder.create(createDraweeHierarchy(), context); - - mLogoControllerListener = new IconControllerListener(mLogoHolder) { - @Override - protected void setDrawable(Drawable d) { - setLogo(d); - } - }; - - mNavIconControllerListener = new IconControllerListener(mNavIconHolder) { - @Override - protected void setDrawable(Drawable d) { - setNavigationIcon(d); - } - }; - - mOverflowIconControllerListener = new IconControllerListener(mOverflowIconHolder) { - @Override - protected void setDrawable(Drawable d) { - setOverflowIcon(d); - } - }; - - } - - private final Runnable mLayoutRunnable = new Runnable() { - @Override - public void run() { - measure( - MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY)); - layout(getLeft(), getTop(), getRight(), getBottom()); - } - }; - - @Override - public void requestLayout() { - super.requestLayout(); - - // The toolbar relies on a measure + layout pass happening after it calls requestLayout(). - // Without this, certain calls (e.g. setLogo) only take effect after a second invalidation. - post(mLayoutRunnable); - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - detachDraweeHolders(); - } - - @Override - public void onStartTemporaryDetach() { - super.onStartTemporaryDetach(); - detachDraweeHolders(); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - attachDraweeHolders(); - } - - @Override - public void onFinishTemporaryDetach() { - super.onFinishTemporaryDetach(); - attachDraweeHolders(); - } - - private void detachDraweeHolders() { - mLogoHolder.onDetach(); - mNavIconHolder.onDetach(); - mOverflowIconHolder.onDetach(); - mActionsHolder.onDetach(); - } - - private void attachDraweeHolders() { - mLogoHolder.onAttach(); - mNavIconHolder.onAttach(); - mOverflowIconHolder.onAttach(); - mActionsHolder.onAttach(); - } - - /* package */ void setLogoSource(@Nullable ReadableMap source) { - setIconSource(source, mLogoControllerListener, mLogoHolder); - } - - /* package */ void setNavIconSource(@Nullable ReadableMap source) { - setIconSource(source, mNavIconControllerListener, mNavIconHolder); - } - - /* package */ void setOverflowIconSource(@Nullable ReadableMap source) { - setIconSource(source, mOverflowIconControllerListener, mOverflowIconHolder); - } - - /* package */ void setActions(@Nullable ReadableArray actions) { - Menu menu = getMenu(); - menu.clear(); - mActionsHolder.clear(); - if (actions != null) { - for (int i = 0; i < actions.size(); i++) { - ReadableMap action = actions.getMap(i); - - MenuItem item = menu.add(Menu.NONE, Menu.NONE, i, action.getString(PROP_ACTION_TITLE)); - - if (action.hasKey(PROP_ACTION_ICON)) { - setMenuItemIcon(item, action.getMap(PROP_ACTION_ICON)); - } - - int showAsAction = action.hasKey(PROP_ACTION_SHOW) - ? action.getInt(PROP_ACTION_SHOW) - : MenuItem.SHOW_AS_ACTION_NEVER; - if (action.hasKey(PROP_ACTION_SHOW_WITH_TEXT) && - action.getBoolean(PROP_ACTION_SHOW_WITH_TEXT)) { - showAsAction = showAsAction | MenuItem.SHOW_AS_ACTION_WITH_TEXT; - } - item.setShowAsAction(showAsAction); - } - } - } - - private void setMenuItemIcon(final MenuItem item, ReadableMap iconSource) { - - DraweeHolder holder = - DraweeHolder.create(createDraweeHierarchy(), getContext()); - ActionIconControllerListener controllerListener = new ActionIconControllerListener(item, holder); - controllerListener.setIconImageInfo(getIconImageInfo(iconSource)); - - setIconSource(iconSource, controllerListener, holder); - - mActionsHolder.add(holder); - - } - - /** - * Sets an icon for a specific icon source. If the uri indicates an icon - * to be somewhere remote (http/https) or on the local filesystem, it uses fresco to load it. - * Otherwise it loads the Drawable from the Resources and directly returns it via a callback - */ - private void setIconSource(ReadableMap source, IconControllerListener controllerListener, DraweeHolder holder) { - - String uri = source != null ? source.getString(PROP_ICON_URI) : null; - - if (uri == null) { - controllerListener.setIconImageInfo(null); - controllerListener.setDrawable(null); - } else if (uri.startsWith("http://") || uri.startsWith("https://") || uri.startsWith("file://")) { - controllerListener.setIconImageInfo(getIconImageInfo(source)); - DraweeController controller = Fresco.newDraweeControllerBuilder() - .setUri(Uri.parse(uri)) - .setControllerListener(controllerListener) - .setOldController(holder.getController()) - .build(); - holder.setController(controller); - holder.getTopLevelDrawable().setVisible(true, true); - } else { - controllerListener.setDrawable(getDrawableByName(uri)); - } - - } - - private GenericDraweeHierarchy createDraweeHierarchy() { - return new GenericDraweeHierarchyBuilder(getResources()) - .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER) - .setFadeDuration(0) - .build(); - } - - private int getDrawableResourceByName(String name) { - return getResources().getIdentifier( - name, - "drawable", - getContext().getPackageName()); - } - - private Drawable getDrawableByName(String name) { - int drawableResId = getDrawableResourceByName(name); - if (drawableResId != 0) { - return getResources().getDrawable(getDrawableResourceByName(name)); - } else { - return null; - } - } - - private IconImageInfo getIconImageInfo(ReadableMap source) { - if (source.hasKey(PROP_ICON_WIDTH) && source.hasKey(PROP_ICON_HEIGHT)) { - final int width = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_WIDTH))); - final int height = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_HEIGHT))); - return new IconImageInfo(width, height); - } else { - return null; - } - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java deleted file mode 100644 index 422d77d18c106e..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java +++ /dev/null @@ -1,267 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.views.toolbar; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Color; -import androidx.core.view.ViewCompat; -import android.util.LayoutDirection; -import android.view.MenuItem; -import android.view.View; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.PixelUtil; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.ViewGroupManager; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.react.views.toolbar.events.ToolbarClickEvent; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * Manages instances of ReactToolbar. - */ -public class ReactToolbarManager extends ViewGroupManager { - - private static final String REACT_CLASS = "ToolbarAndroid"; - private static final int COMMAND_DISMISS_POPUP_MENUS = 1; - - @Override - public String getName() { - return REACT_CLASS; - } - - @Override - protected ReactToolbar createViewInstance(ThemedReactContext reactContext) { - return new ReactToolbar(reactContext); - } - - @ReactProp(name = "logo") - public void setLogo(ReactToolbar view, @Nullable ReadableMap logo) { - view.setLogoSource(logo); - } - - @ReactProp(name = "navIcon") - public void setNavIcon(ReactToolbar view, @Nullable ReadableMap navIcon) { - view.setNavIconSource(navIcon); - } - - @ReactProp(name = "overflowIcon") - public void setOverflowIcon(ReactToolbar view, @Nullable ReadableMap overflowIcon) { - view.setOverflowIconSource(overflowIcon); - } - - @ReactProp(name = "rtl") - public void setRtl(ReactToolbar view, boolean rtl) { - ViewCompat.setLayoutDirection(view, rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR); - } - - @ReactProp(name = "subtitle") - public void setSubtitle(ReactToolbar view, @Nullable String subtitle) { - view.setSubtitle(subtitle); - } - - @ReactProp(name = "subtitleColor", customType = "Color") - public void setSubtitleColor(ReactToolbar view, @Nullable Integer subtitleColor) { - int[] defaultColors = getDefaultColors(view.getContext()); - if (subtitleColor != null) { - view.setSubtitleTextColor(subtitleColor); - } else { - view.setSubtitleTextColor(defaultColors[1]); - } - } - - @ReactProp(name = "title") - public void setTitle(ReactToolbar view, @Nullable String title) { - view.setTitle(title); - } - - @ReactProp(name = "titleColor", customType = "Color") - public void setTitleColor(ReactToolbar view, @Nullable Integer titleColor) { - int[] defaultColors = getDefaultColors(view.getContext()); - if (titleColor != null) { - view.setTitleTextColor(titleColor); - } else { - view.setTitleTextColor(defaultColors[0]); - } - } - - @ReactProp(name = "contentInsetStart", defaultFloat = Float.NaN) - public void setContentInsetStart(ReactToolbar view, float insetStart) { - int inset = Float.isNaN(insetStart) ? - getDefaultContentInsets(view.getContext())[0] : - Math.round(PixelUtil.toPixelFromDIP(insetStart)); - view.setContentInsetsRelative(inset, view.getContentInsetEnd()); - } - - @ReactProp(name = "contentInsetEnd", defaultFloat = Float.NaN) - public void setContentInsetEnd(ReactToolbar view, float insetEnd) { - int inset = Float.isNaN(insetEnd) ? - getDefaultContentInsets(view.getContext())[1] : - Math.round(PixelUtil.toPixelFromDIP(insetEnd)); - view.setContentInsetsRelative(view.getContentInsetStart(), inset); - } - - @ReactProp(name = "nativeActions") - public void setActions(ReactToolbar view, @Nullable ReadableArray actions) { - view.setActions(actions); - } - - @Override - protected void addEventEmitters(final ThemedReactContext reactContext, final ReactToolbar view) { - final EventDispatcher mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher(); - view.setNavigationOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - mEventDispatcher.dispatchEvent( - new ToolbarClickEvent(view.getId(), -1)); - } - }); - - view.setOnMenuItemClickListener( - new ReactToolbar.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem menuItem) { - mEventDispatcher.dispatchEvent( - new ToolbarClickEvent( - view.getId(), - menuItem.getOrder())); - return true; - } - }); - } - - @Nullable - @Override - public Map getExportedViewConstants() { - return MapBuilder.of( - "ShowAsAction", - MapBuilder.of( - "never", MenuItem.SHOW_AS_ACTION_NEVER, - "always", MenuItem.SHOW_AS_ACTION_ALWAYS, - "ifRoom", MenuItem.SHOW_AS_ACTION_IF_ROOM)); - } - - @Override - public boolean needsCustomLayoutForChildren() { - return true; - } - - @Nullable - @Override - public Map getCommandsMap() { - return MapBuilder.of("dismissPopupMenus", COMMAND_DISMISS_POPUP_MENUS); - } - - @Override - public void receiveCommand(ReactToolbar view, int commandType, @Nullable ReadableArray args) { - switch (commandType) { - case COMMAND_DISMISS_POPUP_MENUS: { - view.dismissPopupMenus(); - return; - } - default: - throw new IllegalArgumentException(String.format( - "Unsupported command %d received by %s.", - commandType, - getClass().getSimpleName())); - } - } - - private int[] getDefaultContentInsets(Context context) { - Resources.Theme theme = context.getTheme(); - TypedArray toolbarStyle = null; - TypedArray contentInsets = null; - - try { - toolbarStyle = - theme.obtainStyledAttributes(new int[] {getIdentifier(context, "toolbarStyle")}); - - int toolbarStyleResId = toolbarStyle.getResourceId(0, 0); - - contentInsets = - theme.obtainStyledAttributes( - toolbarStyleResId, - new int[] { - getIdentifier(context, "contentInsetStart"), - getIdentifier(context, "contentInsetEnd"), - }); - - int contentInsetStart = contentInsets.getDimensionPixelSize(0, 0); - int contentInsetEnd = contentInsets.getDimensionPixelSize(1, 0); - - return new int[] {contentInsetStart, contentInsetEnd}; - } finally { - recycleQuietly(toolbarStyle); - recycleQuietly(contentInsets); - } - - } - - private static int[] getDefaultColors(Context context) { - Resources.Theme theme = context.getTheme(); - TypedArray toolbarStyle = null; - TypedArray textAppearances = null; - TypedArray titleTextAppearance = null; - TypedArray subtitleTextAppearance = null; - - try { - toolbarStyle = - theme.obtainStyledAttributes(new int[] {getIdentifier(context, "toolbarStyle")}); - - int toolbarStyleResId = toolbarStyle.getResourceId(0, 0); - textAppearances = - theme.obtainStyledAttributes( - toolbarStyleResId, - new int[] { - getIdentifier(context, "titleTextAppearance"), - getIdentifier(context, "subtitleTextAppearance"), - }); - - int titleTextAppearanceResId = textAppearances.getResourceId(0, 0); - int subtitleTextAppearanceResId = textAppearances.getResourceId(1, 0); - - titleTextAppearance = theme - .obtainStyledAttributes(titleTextAppearanceResId, new int[]{android.R.attr.textColor}); - subtitleTextAppearance = theme - .obtainStyledAttributes(subtitleTextAppearanceResId, new int[]{android.R.attr.textColor}); - - int titleTextColor = titleTextAppearance.getColor(0, Color.BLACK); - int subtitleTextColor = subtitleTextAppearance.getColor(0, Color.BLACK); - - return new int[] {titleTextColor, subtitleTextColor}; - } finally { - recycleQuietly(toolbarStyle); - recycleQuietly(textAppearances); - recycleQuietly(titleTextAppearance); - recycleQuietly(subtitleTextAppearance); - } - } - - private static void recycleQuietly(@Nullable TypedArray style) { - if (style != null) { - style.recycle(); - } - } - - /** - * The appcompat-v7 BUCK dep is listed as a provided_dep, which complains that - * com.facebook.react.R doesn't exist. Since the attributes provided from a parent, we can access - * those attributes dynamically. - */ - private static int getIdentifier(Context context, String name) { - return context.getResources().getIdentifier(name, "attr", context.getPackageName()); - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java deleted file mode 100644 index 9025178c050e1f..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -package com.facebook.react.views.toolbar.events; - -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.uimanager.events.Event; -import com.facebook.react.uimanager.events.RCTEventEmitter; - -/** - * Represents a click on the toolbar. - * Position is meaningful when the click happened on a menu - */ -public class ToolbarClickEvent extends Event { - - private static final String EVENT_NAME = "topSelect"; - private final int position; - - public ToolbarClickEvent(int viewId, int position) { - super(viewId); - this.position = position; - } - - public int getPosition() { - return position; - } - - @Override - public String getEventName() { - return EVENT_NAME; - } - - @Override - public boolean canCoalesce() { - return false; - } - - @Override - public void dispatch(RCTEventEmitter rctEventEmitter) { - WritableMap event = new WritableNativeMap(); - event.putInt("position", getPosition()); - rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event); - } - -} From 022470ce62186ffb1a471a3a92c7bfdd579c824a Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 6 Jun 2019 02:41:36 -0700 Subject: [PATCH 115/330] Remove Map/Set from RN Open Source Summary: This moves Map/Set to fb internal. We do not need them in open source any more but we still need this in some apps at FB that use an old version of JSC. Reviewed By: TheSavior Differential Revision: D14786123 fbshipit-source-id: 1c49b47d547ad30f2d93c00b44382cf410100b67 --- Libraries/Core/InitializeCore.js | 1 - .../Core/__tests__/MapAndSetPolyfills-test.js | 102 --- Libraries/Core/polyfillES6Collections.js | 27 - Libraries/vendor/core/Map.js | 590 ------------------ Libraries/vendor/core/Set.js | 198 ------ .../core/_shouldPolyfillES6Collection.js | 66 -- flow/Map.js | 40 -- flow/Set.js | 36 -- 8 files changed, 1060 deletions(-) delete mode 100644 Libraries/Core/__tests__/MapAndSetPolyfills-test.js delete mode 100644 Libraries/Core/polyfillES6Collections.js delete mode 100644 Libraries/vendor/core/Map.js delete mode 100644 Libraries/vendor/core/Set.js delete mode 100644 Libraries/vendor/core/_shouldPolyfillES6Collection.js delete mode 100644 flow/Map.js delete mode 100644 flow/Set.js diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 263001547b6132..8b9a6a490739d1 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -28,7 +28,6 @@ const start = Date.now(); require('./setUpGlobals'); -require('./polyfillES6Collections'); require('./setUpSystrace'); require('./setUpErrorHandling'); require('./polyfillPromise'); diff --git a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js deleted file mode 100644 index 20f54a0e68d9d5..00000000000000 --- a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+react_native - */ -'use strict'; - -// Save these methods so that we can restore them afterward. -const {freeze, seal, preventExtensions} = Object; - -function setup() { - jest.setMock('../../vendor/core/_shouldPolyfillES6Collection', () => true); -} - -function cleanup() { - Object.assign(Object, {freeze, seal, preventExtensions}); -} - -describe('Map polyfill', () => { - setup(); - - const Map = require('../../vendor/core/Map'); - - it('is not native', () => { - const getCode = Function.prototype.toString.call(Map.prototype.get); - expect(getCode).not.toContain('[native code]'); - expect(getCode).toContain('getIndex'); - }); - - it('should tolerate non-extensible object keys', () => { - const map = new Map(); - const key = Object.create(null); - Object.freeze(key); - map.set(key, key); - expect(map.size).toBe(1); - expect(map.has(key)).toBe(true); - map.delete(key); - expect(map.size).toBe(0); - expect(map.has(key)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const map = new Map(); - const proto = Object.create(null); - const base = Object.create(proto); - map.set(proto, proto); - expect(map.size).toBe(1); - expect(map.has(proto)).toBe(true); - expect(map.has(base)).toBe(false); - map.set(base, base); - expect(map.size).toBe(2); - expect(map.get(proto)).toBe(proto); - expect(map.get(base)).toBe(base); - }); - - afterAll(cleanup); -}); - -describe('Set polyfill', () => { - setup(); - - const Set = require('../../vendor/core/Set'); - - it('is not native', () => { - const addCode = Function.prototype.toString.call(Set.prototype.add); - expect(addCode).not.toContain('[native code]'); - }); - - it('should tolerate non-extensible object elements', () => { - const set = new Set(); - const elem = Object.create(null); - Object.freeze(elem); - set.add(elem); - expect(set.size).toBe(1); - expect(set.has(elem)).toBe(true); - set.add(elem); - expect(set.size).toBe(1); - set.delete(elem); - expect(set.size).toBe(0); - expect(set.has(elem)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const set = new Set(); - const proto = Object.create(null); - const base = Object.create(proto); - set.add(proto); - expect(set.size).toBe(1); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(false); - set.add(base); - expect(set.size).toBe(2); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(true); - }); - - afterAll(cleanup); -}); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js deleted file mode 100644 index b58718540fedca..00000000000000 --- a/Libraries/Core/polyfillES6Collections.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ -'use strict'; - -const {polyfillGlobal} = require('../Utilities/PolyfillFunctions'); - -/** - * Polyfill ES6 collections (Map and Set). - * If you don't need these polyfills, don't use InitializeCore; just directly - * require the modules you need from InitializeCore for setup. - */ -const _shouldPolyfillCollection = require('../vendor/core/_shouldPolyfillES6Collection'); -if (_shouldPolyfillCollection('Map')) { - // $FlowFixMe: even in strict-local mode Flow expects Map to be Flow-typed - polyfillGlobal('Map', () => require('../vendor/core/Map')); -} -if (_shouldPolyfillCollection('Set')) { - // $FlowFixMe: even in strict-local mode Flow expects Set to be Flow-typed - polyfillGlobal('Set', () => require('../vendor/core/Set')); -} diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js deleted file mode 100644 index 4f23b1f4783ab8..00000000000000 --- a/Libraries/vendor/core/Map.js +++ /dev/null @@ -1,590 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native, no-shadow-restricted-names */ - -'use strict'; - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const guid = require('./guid'); -const toIterator = require('./toIterator'); - -module.exports = (function(global, undefined) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - if (!_shouldPolyfillES6Collection('Map')) { - return global.Map; - } - - const hasOwn = Object.prototype.hasOwnProperty; - - /** - * == ES6 Map Collection == - * - * This module is meant to implement a Map collection as described in chapter - * 23.1 of the ES6 specification. - * - * Map objects are collections of key/value pairs where both the keys and - * values may be arbitrary ECMAScript language values. A distinct key value - * may only occur in one key/value pair within the Map's collection. - * - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- deviations from the spec: - * - * 1. The use of untagged frozen objects as keys. - * We decided not to allow and simply throw an error, because this - * implementation of Map works by tagging objects used as Map keys - * with a secret hash property for fast access to the object's place - * in the internal _mapData array. However, to limit the impact of - * this spec deviation, Libraries/Core/InitializeCore.js also wraps - * Object.freeze, Object.seal, and Object.preventExtensions so that - * they tag objects before making them non-extensible, by inserting - * each object into a Map and then immediately removing it. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var map = new Map(iterable); - * - * map.set(key, value); - * map.get(key); // value - * map.has(key); // true - * map.delete(key); // true - * - * var iterator = map.keys(); - * iterator.next(); // {value: key, done: false} - * - * var iterator = map.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = map.entries(); - * iterator.next(); // {value: [key, value], done: false} - * - * map.forEach(function(value, key){ this === thisArg }, thisArg); - * - * map.clear(); // resets map. - */ - - /** - * Constants - */ - - // Kinds of map iterations 23.1.5.3 - const KIND_KEY = 'key'; - const KIND_VALUE = 'value'; - const KIND_KEY_VALUE = 'key+value'; - - // In older browsers we can't create a null-prototype object so we have to - // defend against key collisions with built-in methods. - const KEY_PREFIX = '$map_'; - - // This property will be used as the internal size variable to disallow - // writing and to issue warnings for writings in development. - let SECRET_SIZE_PROP; - if (__DEV__) { - SECRET_SIZE_PROP = '$size' + guid(); - } - - class Map { - /** - * 23.1.1.1 - * Takes an `iterable` which is basically any object that implements a - * Symbol.iterator (@@iterator) method. The iterable is expected to be a - * collection of pairs. Each pair is a key/value pair that will be used - * to instantiate the map. - * - * @param {*} iterable - */ - constructor(iterable) { - if (!isObject(this)) { - throw new TypeError('Wrong map object type.'); - } - - initMap(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - if (!isObject(next.value)) { - throw new TypeError('Expected iterable items to be pair objects.'); - } - this.set(next.value[0], next.value[1]); - } - } - } - - /** - * 23.1.3.1 - * Clears the map from all keys and values. - */ - clear() { - initMap(this); - } - - /** - * 23.1.3.7 - * Check if a key exists in the collection. - * - * @param {*} key - * @return {boolean} - */ - has(key) { - const index = getIndex(this, key); - return !!(index != null && this._mapData[index]); - } - - /** - * 23.1.3.9 - * Adds a key/value pair to the collection. - * - * @param {*} key - * @param {*} value - * @return {map} - */ - set(key, value) { - let index = getIndex(this, key); - - if (index != null && this._mapData[index]) { - this._mapData[index][1] = value; - } else { - index = this._mapData.push([key, value]) - 1; - setIndex(this, key, index); - if (__DEV__) { - this[SECRET_SIZE_PROP] += 1; - } else { - this.size += 1; - } - } - - return this; - } - - /** - * 23.1.3.6 - * Gets a value associated with a key in the collection. - * - * @param {*} key - * @return {*} - */ - get(key) { - const index = getIndex(this, key); - if (index == null) { - return undefined; - } else { - return this._mapData[index][1]; - } - } - - /** - * 23.1.3.3 - * Delete a key/value from the collection. - * - * @param {*} key - * @return {boolean} Whether the key was found and deleted. - */ - delete(key) { - const index = getIndex(this, key); - if (index != null && this._mapData[index]) { - setIndex(this, key, undefined); - this._mapData[index] = undefined; - if (__DEV__) { - this[SECRET_SIZE_PROP] -= 1; - } else { - this.size -= 1; - } - return true; - } else { - return false; - } - } - - /** - * 23.1.3.4 - * Returns an iterator over the key/value pairs (in the form of an Array) in - * the collection. - * - * @return {MapIterator} - */ - entries() { - return new MapIterator(this, KIND_KEY_VALUE); - } - - /** - * 23.1.3.8 - * Returns an iterator over the keys in the collection. - * - * @return {MapIterator} - */ - keys() { - return new MapIterator(this, KIND_KEY); - } - - /** - * 23.1.3.11 - * Returns an iterator over the values pairs in the collection. - * - * @return {MapIterator} - */ - values() { - return new MapIterator(this, KIND_VALUE); - } - - /** - * 23.1.3.5 - * Iterates over the key/value pairs in the collection calling `callback` - * with [value, key, map]. An optional `thisArg` can be passed to set the - * context when `callback` is called. - * - * @param {function} callback - * @param {?object} thisArg - */ - forEach(callback, thisArg) { - if (typeof callback !== 'function') { - throw new TypeError('Callback must be callable.'); - } - - const boundCallback = callback.bind(thisArg || undefined); - const mapData = this._mapData; - - // Note that `mapData.length` should be computed on each iteration to - // support iterating over new items in the map that were added after the - // start of the iteration. - for (let i = 0; i < mapData.length; i++) { - const entry = mapData[i]; - if (entry != null) { - boundCallback(entry[1], entry[0], this); - } - } - } - } - - // 23.1.3.12 - Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries; - - class MapIterator { - /** - * 23.1.5.1 - * Create a `MapIterator` for a given `map`. While this class is private it - * will create objects that will be passed around publicily. - * - * @param {map} map - * @param {string} kind - */ - constructor(map, kind) { - if (!(isObject(map) && map._mapData)) { - throw new TypeError('Object is not a map.'); - } - - if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) { - throw new Error('Invalid iteration kind.'); - } - - this._map = map; - this._nextIndex = 0; - this._kind = kind; - } - - /** - * 23.1.5.2.1 - * Get the next iteration. - * - * @return {object} - */ - next() { - if (!this instanceof Map) { - throw new TypeError('Expected to be called on a MapIterator.'); - } - - const map = this._map; - let index = this._nextIndex; - const kind = this._kind; - - if (map == null) { - return createIterResultObject(undefined, true); - } - - const entries = map._mapData; - - while (index < entries.length) { - const record = entries[index]; - - index += 1; - this._nextIndex = index; - - if (record) { - if (kind === KIND_KEY) { - return createIterResultObject(record[0], false); - } else if (kind === KIND_VALUE) { - return createIterResultObject(record[1], false); - } else if (kind) { - return createIterResultObject(record, false); - } - } - } - - this._map = undefined; - - return createIterResultObject(undefined, true); - } - } - - // We can put this in the class definition once we have computed props - // transform. - // 23.1.5.2.2 - MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() { - return this; - }; - - /** - * Helper Functions. - */ - - /** - * Return an index to map.[[MapData]] array for a given Key. - * - * @param {map} map - * @param {*} key - * @return {?number} - */ - function getIndex(map, key) { - if (isObject(key)) { - const hash = getHash(key); - return map._objectIndex[hash]; - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - return map._stringIndex[prefixedKey]; - } else { - return map._otherIndex[prefixedKey]; - } - } - } - - /** - * Setup an index that refer to the key's location in map.[[MapData]]. - * - * @param {map} map - * @param {*} key - */ - function setIndex(map, key, index) { - const shouldDelete = index == null; - - if (isObject(key)) { - const hash = getHash(key); - if (shouldDelete) { - delete map._objectIndex[hash]; - } else { - map._objectIndex[hash] = index; - } - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - if (shouldDelete) { - delete map._stringIndex[prefixedKey]; - } else { - map._stringIndex[prefixedKey] = index; - } - } else { - if (shouldDelete) { - delete map._otherIndex[prefixedKey]; - } else { - map._otherIndex[prefixedKey] = index; - } - } - } - } - - /** - * Instantiate a map with internal slots. - * - * @param {map} map - */ - function initMap(map) { - // Data structure design inspired by Traceur's Map implementation. - // We maintain an internal array for all the entries. The array is needed - // to remember order. However, to have a reasonable HashMap performance - // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices - // in objects for fast look ups. Indices are split up according to data - // types to avoid collisions. - map._mapData = []; - - // Object index maps from an object "hash" to index. The hash being a unique - // property of our choosing that we associate with the object. Association - // is done by ways of keeping a non-enumerable property on the object. - // Ideally these would be `Object.create(null)` objects but since we're - // trying to support ES3 we'll have to guard against collisions using - // prefixes on the keys rather than rely on null prototype objects. - map._objectIndex = {}; - - // String index maps from strings to index. - map._stringIndex = {}; - - // Numbers, booleans, undefined, and null. - map._otherIndex = {}; - - // Unfortunately we have to support ES3 and cannot have `Map.prototype.size` - // be a getter method but just a regular method. The biggest problem with - // this is safety. Clients can change the size property easily and possibly - // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we - // can do to mitigate use getters and setters in development to disallow - // and issue a warning for changing the `size` property. - if (__DEV__) { - if (isES5) { - // If the `SECRET_SIZE_PROP` property is already defined then we're not - // in the first call to `initMap` (e.g. coming from `map.clear()`) so - // all we need to do is reset the size without defining the properties. - if (hasOwn.call(map, SECRET_SIZE_PROP)) { - map[SECRET_SIZE_PROP] = 0; - } else { - Object.defineProperty(map, SECRET_SIZE_PROP, { - value: 0, - writable: true, - }); - Object.defineProperty(map, 'size', { - set: v => { - console.error( - 'PLEASE FIX ME: You are changing the map size property which ' + - 'should not be writable and will break in production.', - ); - throw new Error('The map size property is not writable.'); - }, - get: () => map[SECRET_SIZE_PROP], - }); - } - - // NOTE: Early return to implement immutable `.size` in DEV. - return; - } - } - - // This is a diviation from the spec. `size` should be a getter on - // `Map.prototype`. However, we have to support IE8. - map.size = 0; - } - - /** - * Check if something is an object. - * - * @param {*} o - * @return {boolean} - */ - function isObject(o) { - return o != null && (typeof o === 'object' || typeof o === 'function'); - } - - /** - * Create an iteration object. - * - * @param {*} value - * @param {boolean} done - * @return {object} - */ - function createIterResultObject(value, done) { - return {value, done}; - } - - // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8. - const isES5 = (function() { - try { - Object.defineProperty({}, 'x', {}); - return true; - } catch (e) { - return false; - } - })(); - - /** - * Check if an object can be extended. - * - * @param {object|array|function|regexp} o - * @return {boolean} - */ - function isExtensible(o) { - if (!isES5) { - return true; - } else { - return Object.isExtensible(o); - } - } - - const getHash = (function() { - const propIsEnumerable = Object.prototype.propertyIsEnumerable; - const hashProperty = '__MAP_POLYFILL_INTERNAL_HASH__'; - let hashCounter = 0; - - const nonExtensibleObjects = []; - const nonExtensibleHashes = []; - - /** - * Get the "hash" associated with an object. - * - * @param {object|array|function|regexp} o - * @return {number} - */ - return function getHash(o) { - if (hasOwn.call(o, hashProperty)) { - return o[hashProperty]; - } - - if (!isES5) { - if ( - hasOwn.call(o, 'propertyIsEnumerable') && - hasOwn.call(o.propertyIsEnumerable, hashProperty) - ) { - return o.propertyIsEnumerable[hashProperty]; - } - } - - if (isExtensible(o)) { - if (isES5) { - Object.defineProperty(o, hashProperty, { - enumerable: false, - writable: false, - configurable: false, - value: ++hashCounter, - }); - return hashCounter; - } - - if (o.propertyIsEnumerable) { - // Since we can't define a non-enumerable property on the object - // we'll hijack one of the less-used non-enumerable properties to - // save our hash on it. Additionally, since this is a function it - // will not show up in `JSON.stringify` which is what we want. - o.propertyIsEnumerable = function() { - return propIsEnumerable.apply(this, arguments); - }; - return (o.propertyIsEnumerable[hashProperty] = ++hashCounter); - } - } - - // If the object is not extensible, fall back to storing it in an - // array and using Array.prototype.indexOf to find it. - let index = nonExtensibleObjects.indexOf(o); - if (index < 0) { - index = nonExtensibleObjects.length; - nonExtensibleObjects[index] = o; - nonExtensibleHashes[index] = ++hashCounter; - } - return nonExtensibleHashes[index]; - }; - })(); - - return Map; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js deleted file mode 100644 index 564f530b9afd8a..00000000000000 --- a/Libraries/vendor/core/Set.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native */ - -'use strict'; - -const Map = require('./Map'); - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const toIterator = require('./toIterator'); - -module.exports = (function(global) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - // These checks are adapted from es6-shim https://fburl.com/34437854 - if (!_shouldPolyfillES6Collection('Set')) { - return global.Set; - } - - /** - * == ES6 Set Collection == - * - * This module is meant to implement a Set collection as described in chapter - * 23.2 of the ES6 specification. - * - * Set objects are collections of unique values. Where values can be any - * JavaScript value. - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- diviations from the spec: - * - * 1. The use of frozen objects as keys. @see Map module for more on this. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var set = new set(iterable); - * - * set.set(value); - * set.has(value); // true - * set.delete(value); // true - * - * var iterator = set.keys(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.entries(); - * iterator.next(); // {value: [value, value], done: false} - * - * set.forEach(function(value, value){ this === thisArg }, thisArg); - * - * set.clear(); // resets set. - */ - - class Set { - /** - * 23.2.1.1 - * - * Takes an optional `iterable` (which is basically any object that - * implements a Symbol.iterator (@@iterator) method). That is a collection - * of values used to instantiate the set. - * - * @param {*} iterable - */ - constructor(iterable) { - if ( - this == null || - (typeof this !== 'object' && typeof this !== 'function') - ) { - throw new TypeError('Wrong set object type.'); - } - - initSet(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - this.add(next.value); - } - } - } - - /** - * 23.2.3.1 - * - * If it doesn't already exist in the collection a `value` is added. - * - * @param {*} value - * @return {set} - */ - add(value) { - this._map.set(value, value); - this.size = this._map.size; - return this; - } - - /** - * 23.2.3.2 - * - * Clears the set. - */ - clear() { - initSet(this); - } - - /** - * 23.2.3.4 - * - * Deletes a `value` from the collection if it exists. - * Returns true if the value was found and deleted and false otherwise. - * - * @param {*} value - * @return {boolean} - */ - delete(value) { - const ret = this._map.delete(value); - this.size = this._map.size; - return ret; - } - - /** - * 23.2.3.5 - * - * Returns an iterator over a collection of [value, value] tuples. - */ - entries() { - return this._map.entries(); - } - - /** - * 23.2.3.6 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {function} callback - */ - forEach(callback) { - const thisArg = arguments[1]; - const it = this._map.keys(); - let next; - while (!(next = it.next()).done) { - callback.call(thisArg, next.value, next.value, this); - } - } - - /** - * 23.2.3.7 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {*} value - * @return {boolean} - */ - has(value) { - return this._map.has(value); - } - - /** - * 23.2.3.7 - * - * Returns an iterator over the colleciton of values. - */ - values() { - return this._map.values(); - } - } - - // 23.2.3.11 - Set.prototype[toIterator.ITERATOR_SYMBOL] = Set.prototype.values; - - // 23.2.3.7 - Set.prototype.keys = Set.prototype.values; - - function initSet(set) { - set._map = new Map(); - set.size = set._map.size; - } - - return Set; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js deleted file mode 100644 index 1ba893c5aebdbe..00000000000000 --- a/Libraries/vendor/core/_shouldPolyfillES6Collection.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @flow strict - */ - -'use strict'; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used. - */ -function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { - const Collection = global[collectionName]; - if (Collection == null) { - return true; - } - - // The iterator protocol depends on `Symbol.iterator`. If a collection is - // implemented, but `Symbol` is not, it's going to break iteration because - // we'll be using custom "@@iterator" instead, which is not implemented on - // native collections. - if (typeof global.Symbol !== 'function') { - return true; - } - - const proto = Collection.prototype; - - // These checks are adapted from es6-shim: https://fburl.com/34437854 - // NOTE: `isCallableWithoutNew` and `!supportsSubclassing` are not checked - // because they make debugging with "break on exceptions" difficult. - return ( - Collection == null || - typeof Collection !== 'function' || - typeof proto.clear !== 'function' || - new Collection().size !== 0 || - typeof proto.keys !== 'function' || - typeof proto.forEach !== 'function' - ); -} - -const cache: {[name: string]: boolean} = {}; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used and caches this result. - * Make sure to make a first call to this function before a corresponding - * property on global was overriden in any way. - */ -function _shouldPolyfillES6Collection(collectionName: string) { - let result = cache[collectionName]; - if (result !== undefined) { - return result; - } - - result = _shouldActuallyPolyfillES6Collection(collectionName); - cache[collectionName] = result; - return result; -} - -module.exports = _shouldPolyfillES6Collection; diff --git a/flow/Map.js b/flow/Map.js deleted file mode 100644 index c8e830529798ff..00000000000000 --- a/flow/Map.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Map. - -declare module 'Map' { - // Use the name "MapPolyfill" so that we don't get confusing error - // messages about "Using Map instead of Map". - declare class MapPolyfill { - @@iterator(): Iterator<[K, V]>; - constructor(_: void): MapPolyfill; - constructor(_: null): MapPolyfill; - constructor( - iterable: Iterable<[Key, Value]>, - ): MapPolyfill; - clear(): void; - delete(key: K): boolean; - entries(): Iterator<[K, V]>; - forEach( - callbackfn: (value: V, index: K, map: MapPolyfill) => mixed, - thisArg?: any, - ): void; - get(key: K): V | void; - has(key: K): boolean; - keys(): Iterator; - set(key: K, value: V): MapPolyfill; - size: number; - values(): Iterator; - } - - declare module.exports: typeof MapPolyfill; -} diff --git a/flow/Set.js b/flow/Set.js deleted file mode 100644 index 64099c2a6028c3..00000000000000 --- a/flow/Set.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @nolint - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Set. - -declare module 'Set' { - // Use the name "SetPolyfill" so that we don't get confusing error - // messages about "Using Set instead of Set". - declare class SetPolyfill { - @@iterator(): Iterator; - constructor(iterable: ?Iterable): void; - add(value: T): SetPolyfill; - clear(): void; - delete(value: T): boolean; - entries(): Iterator<[T, T]>; - forEach( - callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, - thisArg?: any, - ): void; - has(value: T): boolean; - keys(): Iterator; - size: number; - values(): Iterator; - } - - declare module.exports: typeof SetPolyfill; -} From 67e589ce06449f690017079dbbcf2a2a93eff239 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 6 Jun 2019 03:00:04 -0700 Subject: [PATCH 116/330] Move NetInfo Android files to FB internal Summary: This moves the Android related files to FB internal and moves the BUCK deps around. Reviewed By: fkgozali Differential Revision: D15392573 fbshipit-source-id: 251d2766729ed42a6fe312b3ab9c6b8f1a8c46d1 --- .../com/facebook/react/modules/netinfo/BUCK | 26 -- .../react/modules/netinfo/NetInfoModule.java | 268 ------------------ .../main/java/com/facebook/react/shell/BUCK | 1 - .../react/shell/MainReactPackage.java | 10 - 4 files changed, 305 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK deleted file mode 100644 index fc907537682617..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK +++ /dev/null @@ -1,26 +0,0 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_android_library") - -rn_android_library( - name = "netinfo", - srcs = glob(["**/*.java"]), - is_androidx = True, - provided_deps = [ - react_native_dep("third-party/android/androidx:annotation"), - react_native_dep("third-party/android/androidx:core"), - react_native_dep("third-party/android/androidx:fragment"), - react_native_dep("third-party/android/androidx:legacy-support-core-ui"), - react_native_dep("third-party/android/androidx:legacy-support-core-utils"), - ], - visibility = [ - "PUBLIC", - ], - deps = [ - react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), - react_native_dep("third-party/java/infer-annotations:infer-annotations"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/module/annotations:annotations"), - react_native_target("java/com/facebook/react/modules/core:core"), - ], -) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java deleted file mode 100644 index 56a953d06c4ec7..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java +++ /dev/null @@ -1,268 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.netinfo; - -import android.annotation.SuppressLint; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import androidx.core.net.ConnectivityManagerCompat; -import android.telephony.TelephonyManager; - -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.module.annotations.ReactModule; - -import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; - -/** - * Module that monitors and provides information about the connectivity state of the device. - */ -@SuppressLint("MissingPermission") -@ReactModule(name = NetInfoModule.NAME) -public class NetInfoModule extends ReactContextBaseJavaModule - implements LifecycleEventListener { - - // Based on the ConnectionType enum described in the W3C Network Information API spec - // (https://wicg.github.io/netinfo/). - private static final String CONNECTION_TYPE_BLUETOOTH = "bluetooth"; - private static final String CONNECTION_TYPE_CELLULAR = "cellular"; - private static final String CONNECTION_TYPE_ETHERNET = "ethernet"; - private static final String CONNECTION_TYPE_NONE = "none"; - private static final String CONNECTION_TYPE_UNKNOWN = "unknown"; - private static final String CONNECTION_TYPE_WIFI = "wifi"; - private static final String CONNECTION_TYPE_WIMAX = "wimax"; - - // Based on the EffectiveConnectionType enum described in the W3C Network Information API spec - // (https://wicg.github.io/netinfo/). - private static final String EFFECTIVE_CONNECTION_TYPE_UNKNOWN = "unknown"; - private static final String EFFECTIVE_CONNECTION_TYPE_2G = "2g"; - private static final String EFFECTIVE_CONNECTION_TYPE_3G = "3g"; - private static final String EFFECTIVE_CONNECTION_TYPE_4G = "4g"; - - private static final String CONNECTION_TYPE_NONE_DEPRECATED = "NONE"; - private static final String CONNECTION_TYPE_UNKNOWN_DEPRECATED = "UNKNOWN"; - - private static final String MISSING_PERMISSION_MESSAGE = - "To use NetInfo on Android, add the following to your AndroidManifest.xml:\n" + - ""; - - private static final String ERROR_MISSING_PERMISSION = "E_MISSING_PERMISSION"; - public static final String NAME = "NetInfo"; - - private final ConnectivityManager mConnectivityManager; - private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver; - private boolean mNoNetworkPermission = false; - - private String mConnectivityDeprecated = CONNECTION_TYPE_UNKNOWN_DEPRECATED; - private String mConnectionType = CONNECTION_TYPE_UNKNOWN; - private String mEffectiveConnectionType = EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - - public NetInfoModule(ReactApplicationContext reactContext) { - super(reactContext); - mConnectivityManager = - (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver(); - } - - @Override - public void onHostResume() { - registerReceiver(); - } - - @Override - public void onHostPause() { - unregisterReceiver(); - } - - @Override - public void onHostDestroy() { - } - - @Override - public void initialize() { - getReactApplicationContext().addLifecycleEventListener(this); - } - - @Override - public String getName() { - return NAME; - } - - @ReactMethod - public void getCurrentConnectivity(Promise promise) { - if (mNoNetworkPermission) { - promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE); - return; - } - promise.resolve(createConnectivityEventMap()); - } - - @ReactMethod - public void isConnectionMetered(Promise promise) { - if (mNoNetworkPermission) { - promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE); - return; - } - promise.resolve(ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager)); - } - - private void registerReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - getReactApplicationContext().registerReceiver(mConnectivityBroadcastReceiver, filter); - mConnectivityBroadcastReceiver.setRegistered(true); - updateAndSendConnectionType(); - } - - private void unregisterReceiver() { - if (mConnectivityBroadcastReceiver.isRegistered()) { - getReactApplicationContext().unregisterReceiver(mConnectivityBroadcastReceiver); - mConnectivityBroadcastReceiver.setRegistered(false); - } - } - - private void updateAndSendConnectionType() { - String connectionType = CONNECTION_TYPE_UNKNOWN; - String effectiveConnectionType = EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - - try { - NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); - if (networkInfo == null || !networkInfo.isConnected()) { - connectionType = CONNECTION_TYPE_NONE; - } else { - int networkType = networkInfo.getType(); - switch (networkType) { - case ConnectivityManager.TYPE_BLUETOOTH: - connectionType = CONNECTION_TYPE_BLUETOOTH; - break; - case ConnectivityManager.TYPE_ETHERNET: - connectionType = CONNECTION_TYPE_ETHERNET; - break; - case ConnectivityManager.TYPE_MOBILE: - case ConnectivityManager.TYPE_MOBILE_DUN: - connectionType = CONNECTION_TYPE_CELLULAR; - effectiveConnectionType = getEffectiveConnectionType(networkInfo); - break; - case ConnectivityManager.TYPE_WIFI: - connectionType = CONNECTION_TYPE_WIFI; - break; - case ConnectivityManager.TYPE_WIMAX: - connectionType = CONNECTION_TYPE_WIMAX; - break; - default: - connectionType = CONNECTION_TYPE_UNKNOWN; - break; - } - } - } catch (SecurityException e) { - mNoNetworkPermission = true; - connectionType = CONNECTION_TYPE_UNKNOWN; - } - - String currentConnectivity = getCurrentConnectionType(); - // It is possible to get multiple broadcasts for the same connectivity change, so we only - // update and send an event when the connectivity has indeed changed. - if (!connectionType.equalsIgnoreCase(mConnectionType) || - !effectiveConnectionType.equalsIgnoreCase(mEffectiveConnectionType) || - !currentConnectivity.equalsIgnoreCase(mConnectivityDeprecated)) { - mConnectionType = connectionType; - mEffectiveConnectionType = effectiveConnectionType; - mConnectivityDeprecated = currentConnectivity; - sendConnectivityChangedEvent(); - } - } - - private String getCurrentConnectionType() { - try { - NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); - if (networkInfo == null || !networkInfo.isConnected()) { - return CONNECTION_TYPE_NONE_DEPRECATED; - } else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) { - return networkInfo.getTypeName().toUpperCase(); - } else { - return CONNECTION_TYPE_UNKNOWN_DEPRECATED; - } - } catch (SecurityException e) { - mNoNetworkPermission = true; - return CONNECTION_TYPE_UNKNOWN_DEPRECATED; - } - } - - private String getEffectiveConnectionType(NetworkInfo networkInfo) { - switch (networkInfo.getSubtype()) { - case TelephonyManager.NETWORK_TYPE_1xRTT: - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_IDEN: - return EFFECTIVE_CONNECTION_TYPE_2G; - case TelephonyManager.NETWORK_TYPE_EHRPD: - case TelephonyManager.NETWORK_TYPE_EVDO_0: - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_UMTS: - return EFFECTIVE_CONNECTION_TYPE_3G; - case TelephonyManager.NETWORK_TYPE_HSPAP: - case TelephonyManager.NETWORK_TYPE_LTE: - return EFFECTIVE_CONNECTION_TYPE_4G; - case TelephonyManager.NETWORK_TYPE_UNKNOWN: - default: - return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - } - } - - private void sendConnectivityChangedEvent() { - getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class) - .emit("networkStatusDidChange", createConnectivityEventMap()); - } - - private WritableMap createConnectivityEventMap() { - WritableMap event = new WritableNativeMap(); - event.putString("network_info", mConnectivityDeprecated); - event.putString("connectionType", mConnectionType); - event.putString("effectiveConnectionType", mEffectiveConnectionType); - return event; - } - - /** - * Class that receives intents whenever the connection type changes. - * NB: It is possible on some devices to receive certain connection type changes multiple times. - */ - private class ConnectivityBroadcastReceiver extends BroadcastReceiver { - - //TODO: Remove registered check when source of crash is found. t9846865 - private boolean isRegistered = false; - - public void setRegistered(boolean registered) { - isRegistered = registered; - } - - public boolean isRegistered() { - return isRegistered; - } - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - updateAndSendConnectionType(); - } - } - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index fc134a5af2d35d..ddd632a1b4f12d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -38,7 +38,6 @@ rn_android_library( react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), react_native_target("java/com/facebook/react/modules/image:image"), react_native_target("java/com/facebook/react/modules/intent:intent"), - react_native_target("java/com/facebook/react/modules/netinfo:netinfo"), react_native_target("java/com/facebook/react/modules/network:network"), react_native_target("java/com/facebook/react/modules/permissions:permissions"), react_native_target("java/com/facebook/react/modules/share:share"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index 3d1c17ae4dce3a..cf1f81113f8028 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -28,7 +28,6 @@ import com.facebook.react.modules.i18nmanager.I18nManagerModule; import com.facebook.react.modules.image.ImageLoaderModule; import com.facebook.react.modules.intent.IntentModule; -import com.facebook.react.modules.netinfo.NetInfoModule; import com.facebook.react.modules.network.NetworkingModule; import com.facebook.react.modules.permissions.PermissionsModule; import com.facebook.react.modules.share.ShareModule; @@ -87,7 +86,6 @@ IntentModule.class, NativeAnimatedModule.class, NetworkingModule.class, - NetInfoModule.class, PermissionsModule.class, ShareModule.class, StatusBarModule.class, @@ -251,14 +249,6 @@ public NativeModule get() { return new NetworkingModule(context); } }), - ModuleSpec.nativeModuleSpec( - NetInfoModule.class, - new Provider() { - @Override - public NativeModule get() { - return new NetInfoModule(context); - } - }), ModuleSpec.nativeModuleSpec( PermissionsModule.class, new Provider() { From 831f5fe210a3ffd827a8ab64bc868456df971397 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 6 Jun 2019 04:04:59 -0700 Subject: [PATCH 117/330] Fixes race condition of Network module (#25156) Summary: There exists race condition in `sendRequest:withDelegate:` method, it can do the session creation multiple times, because we don't lock that, which would leads `EXC_BAD_ACCESS` because use and deallocated session concurrently, we can refer to how to create a singleton safely. Related https://github.com/facebook/react-native/issues/25152. ## Changelog [iOS] [Fixed] - Fixes race condition of Network module Pull Request resolved: https://github.com/facebook/react-native/pull/25156 Differential Revision: D15671734 Pulled By: sammy-SC fbshipit-source-id: 5021e6cf33c2b55e3f7adf573ab5c8e6a8d82e23 --- Libraries/Network/RCTHTTPRequestHandler.mm | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/Libraries/Network/RCTHTTPRequestHandler.mm b/Libraries/Network/RCTHTTPRequestHandler.mm index 76131fa69f7797..9a555fab4e205c 100644 --- a/Libraries/Network/RCTHTTPRequestHandler.mm +++ b/Libraries/Network/RCTHTTPRequestHandler.mm @@ -29,12 +29,12 @@ @implementation RCTHTTPRequestHandler - (void)invalidate { - dispatch_async(self->_methodQueue, ^{ - [self->_session invalidateAndCancel]; - self->_session = nil; - }); + std::lock_guard lock(_mutex); + [self->_session invalidateAndCancel]; + self->_session = nil; } +// Needs to lock before call this method. - (BOOL)isValid { // if session == nil and delegates != nil, we've been invalidated @@ -58,6 +58,7 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request - (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate { + std::lock_guard lock(_mutex); // Lazy setup if (!_session && [self isValid]) { // You can override default NSURLSession instance property allowsCellularAccess (default value YES) @@ -83,19 +84,12 @@ - (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request delegate:self delegateQueue:callbackQueue]; - std::lock_guard lock(_mutex); _delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:0]; } - __block NSURLSessionDataTask *task = nil; - dispatch_sync(self->_methodQueue, ^{ - task = [self->_session dataTaskWithRequest:request]; - }); - { - std::lock_guard lock(_mutex); - [_delegates setObject:delegate forKey:task]; - } + NSURLSessionDataTask *task = [_session dataTaskWithRequest:request]; + [_delegates setObject:delegate forKey:task]; [task resume]; return task; } From 417e191a1cfd6a049d1d4b0a511f87aa7f176082 Mon Sep 17 00:00:00 2001 From: Brian Zhao Date: Thu, 6 Jun 2019 04:24:12 -0700 Subject: [PATCH 118/330] Correctly bypass sync calls in UIManager during remote debugging (#25162) Summary: Remote debugging stopped working (since 0.58, according to #23254). See https://github.com/facebook/react-native/issues/23254#issuecomment-474692753 for repro steps. The root cause is incorrect checks for Chrome debugging environment in `UIManager.js`. - In one place where sync function `lazilyLoadView` should be avoided, we effectively use `if (__DEV__ && !global.nativeCallSyncHook)` to check remote debugging, which misses ship flavor (i.e. `__DEV__` is false). - In another place where we want to pre-populate view managers' constants to avoid calling sync function `getConstantsForViewManager`, `if (__DEV__)` is used, also missing ship flavor. This PR fixes both checks, only using the absense of `global.nativeCallSyncHook` to determine remote debugging environments. ## Changelog [JavaScript] [Fixed] - Correctly bypass sync calls in UIManager during remote debugging Pull Request resolved: https://github.com/facebook/react-native/pull/25162 Differential Revision: D15692492 Pulled By: cpojer fbshipit-source-id: 173b688f140916b767fcdbbaaf68a5c303adbcd1 --- Libraries/ReactNative/UIManager.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index e7dd0691724881..19dfa44853a16e 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -78,10 +78,8 @@ const UIManagerJS: UIManagerJSInterface = { // If we're in the Chrome Debugger, let's not even try calling the sync // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { - return config; - } + if (!global.nativeCallSyncHook) { + return config; } if ( @@ -182,7 +180,7 @@ if (Platform.OS === 'ios') { } } -if (__DEV__) { +if (!global.nativeCallSyncHook) { Object.keys(getConstants()).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { From bdc530b9bbf6099563d64fb573c4e6cbc93f9c5d Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Thu, 6 Jun 2019 04:48:32 -0700 Subject: [PATCH 119/330] Fix connection of animated nodes and scroll offset with useNativeDriver. (#24177) Summary: Add example showing regression before this fix is applied. https://github.com/facebook/react-native/pull/18187 Was found to introduce a regression in some internal facebook code-base end to end test which couldn't be shared. I was able to create a reproducible demo of a regression I found, and made a fix for it. Hopefully this will fix the internal test, such that the pr can stay merged. ## Changelog [GENERAL] [Fixed] - Fix connection of animated nodes and scroll offset with useNativeDriver. Pull Request resolved: https://github.com/facebook/react-native/pull/24177 Reviewed By: rickhanlonii Differential Revision: D14845617 Pulled By: cpojer fbshipit-source-id: 1f121dbe773b0cde2adf1ee5a8c3c0266034e50d --- .../Animated/src/NativeAnimatedHelper.js | 25 +++- .../Animated/src/animations/Animation.js | 2 + .../src/nodes/AnimatedInterpolation.js | 11 +- Libraries/Animated/src/nodes/AnimatedNode.js | 2 +- Libraries/Animated/src/nodes/AnimatedProps.js | 1 + Libraries/Animated/src/nodes/AnimatedStyle.js | 4 +- .../Nodes/RCTInterpolationAnimatedNode.m | 110 +++++++++++++++++- .../Nodes/RCTPropsAnimatedNode.m | 9 +- .../Nodes/RCTValueAnimatedNode.h | 1 + .../ScrollView/ScrollViewAnimatedExample.js | 103 ++++++++++++++++ RNTester/js/utils/RNTesterList.android.js | 4 + RNTester/js/utils/RNTesterList.ios.js | 5 + .../animated/InterpolationAnimatedNode.java | 98 +++++++++++++++- .../react/animated/PropsAnimatedNode.java | 7 +- .../react/animated/ValueAnimatedNode.java | 5 + 15 files changed, 366 insertions(+), 21 deletions(-) create mode 100644 RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index a5352046fbbf9f..2128123963a837 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -27,11 +27,25 @@ let __nativeAnimationIdCount = 1; /* used for started animations */ let nativeEventEmitter; +let queueConnections = false; +let queue = []; + /** * Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for * the native module methods */ const API = { + enableQueue: function(): void { + queueConnections = true; + }, + disableQueue: function(): void { + invariant(NativeAnimatedModule, 'Native animated module is not available'); + queueConnections = false; + while (queue.length) { + const args = queue.shift(); + NativeAnimatedModule.connectAnimatedNodes(args[0], args[1]); + } + }, createAnimatedNode: function(tag: ?number, config: AnimatedNodeConfig): void { invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.createAnimatedNode(tag, config); @@ -46,6 +60,10 @@ const API = { }, connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void { invariant(NativeAnimatedModule, 'Native animated module is not available'); + if (queueConnections) { + queue.push([parentTag, childTag]); + return; + } NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag); }, disconnectAnimatedNodes: function( @@ -197,7 +215,7 @@ function addWhitelistedInterpolationParam(param: string): void { function validateTransform( configs: Array< | {type: 'animated', property: string, nodeTag: ?number} - | {type: 'static', property: string, value: number}, + | {type: 'static', property: string, value: number | string}, >, ): void { configs.forEach(config => { @@ -263,7 +281,7 @@ function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean { return config.useNativeDriver || false; } -function transformDataType(value: number | string): number { +function transformDataType(value: number | string): number | string { // Change the string type to number type so we can reuse the same logic in // iOS and Android platform if (typeof value !== 'string') { @@ -274,8 +292,7 @@ function transformDataType(value: number | string): number { const radians = (degrees * Math.PI) / 180.0; return radians; } else { - // Assume radians - return parseFloat(value) || 0; + return value; } } diff --git a/Libraries/Animated/src/animations/Animation.js b/Libraries/Animated/src/animations/Animation.js index 32ccb1e72f0832..24482d22b7ccfc 100644 --- a/Libraries/Animated/src/animations/Animation.js +++ b/Libraries/Animated/src/animations/Animation.js @@ -56,7 +56,9 @@ class Animation { onEnd && onEnd(result); } __startNativeAnimation(animatedValue: AnimatedValue): void { + NativeAnimatedHelper.API.enableQueue(); animatedValue.__makeNative(); + NativeAnimatedHelper.API.disableQueue(); this.__nativeId = NativeAnimatedHelper.generateNewAnimationId(); NativeAnimatedHelper.API.startAnimatingNode( this.__nativeId, diff --git a/Libraries/Animated/src/nodes/AnimatedInterpolation.js b/Libraries/Animated/src/nodes/AnimatedInterpolation.js index d4df33a2f7d5e2..19387984ccf64b 100644 --- a/Libraries/Animated/src/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/src/nodes/AnimatedInterpolation.js @@ -181,7 +181,7 @@ function colorToRgba(input: string): string { return `rgba(${r}, ${g}, ${b}, ${a})`; } -const stringShapeRegex = /[0-9\.-]+/g; +const stringShapeRegex = /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/g; /** * Supports string shapes by extracting numbers so new values can be computed, @@ -242,10 +242,11 @@ function createInterpolationFromStringOutputRange( // -> // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' return outputRange[0].replace(stringShapeRegex, () => { - const val = +interpolations[i++](input); - const rounded = - shouldRound && i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000; - return String(rounded); + let val = +interpolations[i++](input); + if (shouldRound) { + val = i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000; + } + return String(val); }); }; } diff --git a/Libraries/Animated/src/nodes/AnimatedNode.js b/Libraries/Animated/src/nodes/AnimatedNode.js index b90b4c185b8ec6..f6bb39648a80fe 100644 --- a/Libraries/Animated/src/nodes/AnimatedNode.js +++ b/Libraries/Animated/src/nodes/AnimatedNode.js @@ -157,11 +157,11 @@ class AnimatedNode { ); if (this.__nativeTag == null) { const nativeTag: ?number = NativeAnimatedHelper.generateNewNodeTag(); + this.__nativeTag = nativeTag; NativeAnimatedHelper.API.createAnimatedNode( nativeTag, this.__getNativeConfig(), ); - this.__nativeTag = nativeTag; this.__shouldUpdateListenersForNewNativeTag = true; } return this.__nativeTag; diff --git a/Libraries/Animated/src/nodes/AnimatedProps.js b/Libraries/Animated/src/nodes/AnimatedProps.js index 23866ed4356aff..d6914d23bd8a31 100644 --- a/Libraries/Animated/src/nodes/AnimatedProps.js +++ b/Libraries/Animated/src/nodes/AnimatedProps.js @@ -151,6 +151,7 @@ class AnimatedProps extends AnimatedNode { for (const propKey in this._props) { const value = this._props[propKey]; if (value instanceof AnimatedNode) { + value.__makeNative(); propsConfig[propKey] = value.__getNativeTag(); } } diff --git a/Libraries/Animated/src/nodes/AnimatedStyle.js b/Libraries/Animated/src/nodes/AnimatedStyle.js index 4830b2e8d0c1a4..1219bda5962fa4 100644 --- a/Libraries/Animated/src/nodes/AnimatedStyle.js +++ b/Libraries/Animated/src/nodes/AnimatedStyle.js @@ -108,7 +108,9 @@ class AnimatedStyle extends AnimatedWithChildren { const styleConfig = {}; for (const styleKey in this._style) { if (this._style[styleKey] instanceof AnimatedNode) { - styleConfig[styleKey] = this._style[styleKey].__getNativeTag(); + const style = this._style[styleKey]; + style.__makeNative(); + styleConfig[styleKey] = style.__getNativeTag(); } // Non-animated styles are set using `setNativeProps`, no need // to pass those as a part of the node config diff --git a/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m index 0fbaf57d4b4ac4..1fdadc263d538e 100644 --- a/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m @@ -9,27 +9,90 @@ #import "RCTAnimationUtils.h" +static NSRegularExpression *regex; + @implementation RCTInterpolationAnimatedNode { __weak RCTValueAnimatedNode *_parentNode; NSArray *_inputRange; NSArray *_outputRange; + NSArray *> *_outputs; + NSArray *_soutputRange; NSString *_extrapolateLeft; NSString *_extrapolateRight; + NSUInteger _numVals; + bool _hasStringOutput; + bool _shouldRound; + NSArray *_matches; } - (instancetype)initWithTag:(NSNumber *)tag config:(NSDictionary *)config { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *fpRegex = @"[+-]?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?"; + regex = [NSRegularExpression regularExpressionWithPattern:fpRegex options:NSRegularExpressionCaseInsensitive error:nil]; + }); if ((self = [super initWithTag:tag config:config])) { _inputRange = [config[@"inputRange"] copy]; NSMutableArray *outputRange = [NSMutableArray array]; + NSMutableArray *soutputRange = [NSMutableArray array]; + NSMutableArray *> *_outputRanges = [NSMutableArray array]; + + _hasStringOutput = NO; for (id value in config[@"outputRange"]) { if ([value isKindOfClass:[NSNumber class]]) { [outputRange addObject:value]; + } else if ([value isKindOfClass:[NSString class]]) { + /** + * Supports string shapes by extracting numbers so new values can be computed, + * and recombines those values into new strings of the same shape. Supports + * things like: + * + * rgba(123, 42, 99, 0.36) // colors + * -45deg // values with units + */ + NSMutableArray *output = [NSMutableArray array]; + [_outputRanges addObject:output]; + [soutputRange addObject:value]; + + _matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; + for (NSTextCheckingResult *match in _matches) { + NSString* strNumber = [value substringWithRange:match.range]; + [output addObject:[NSNumber numberWithDouble:strNumber.doubleValue]]; + } + + _hasStringOutput = YES; + [outputRange addObject:[output objectAtIndex:0]]; + } + } + if (_hasStringOutput) { + // ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)'] + // -> + // [ + // [0, 50], + // [100, 150], + // [200, 250], + // [0, 0.5], + // ] + _numVals = [_matches count]; + NSString *value = [soutputRange objectAtIndex:0]; + _shouldRound = [value containsString:@"rgb"]; + _matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; + NSMutableArray *> *outputs = [NSMutableArray arrayWithCapacity:_numVals]; + NSUInteger size = [soutputRange count]; + for (NSUInteger j = 0; j < _numVals; j++) { + NSMutableArray *output = [NSMutableArray arrayWithCapacity:size]; + [outputs addObject:output]; + for (int i = 0; i < size; i++) { + [output addObject:[[_outputRanges objectAtIndex:i] objectAtIndex:j]]; + } } + _outputs = [outputs copy]; } _outputRange = [outputRange copy]; + _soutputRange = [soutputRange copy]; _extrapolateLeft = config[@"extrapolateLeft"]; _extrapolateRight = config[@"extrapolateRight"]; } @@ -61,11 +124,48 @@ - (void)performUpdate CGFloat inputValue = _parentNode.value; - self.value = RCTInterpolateValueInRange(inputValue, - _inputRange, - _outputRange, - _extrapolateLeft, - _extrapolateRight); + CGFloat interpolated = RCTInterpolateValueInRange(inputValue, + _inputRange, + _outputRange, + _extrapolateLeft, + _extrapolateRight); + self.value = interpolated; + if (_hasStringOutput) { + // 'rgba(0, 100, 200, 0)' + // -> + // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' + if (_numVals > 1) { + NSString *text = _soutputRange[0]; + NSMutableString *formattedText = [NSMutableString stringWithString:text]; + NSUInteger i = _numVals; + for (NSTextCheckingResult *match in [_matches reverseObjectEnumerator]) { + CGFloat val = RCTInterpolateValueInRange(inputValue, + _inputRange, + _outputs[--i], + _extrapolateLeft, + _extrapolateRight); + NSString *str; + if (_shouldRound) { + // rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to + // round the opacity (4th column). + bool isAlpha = i == 3; + CGFloat rounded = isAlpha ? round(val * 1000) / 1000 : round(val); + str = isAlpha ? [NSString stringWithFormat:@"%1.3f", rounded] : [NSString stringWithFormat:@"%1.0f", rounded]; + } else { + NSNumber *numberValue = [NSNumber numberWithDouble:val]; + str = [numberValue stringValue]; + } + + [formattedText replaceCharactersInRange:[match range] withString:str]; + } + self.animatedObject = formattedText; + } else { + self.animatedObject = [regex stringByReplacingMatchesInString:_soutputRange[0] + options:0 + range:NSMakeRange(0, _soutputRange[0].length) + withTemplate:[NSString stringWithFormat:@"%1f", interpolated]]; + } + } } @end diff --git a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m index 0a9a33434fb461..37f81a148e6821 100644 --- a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m @@ -115,8 +115,13 @@ - (void)performUpdate } else if ([parentNode isKindOfClass:[RCTValueAnimatedNode class]]) { NSString *property = [self propertyNameForParentTag:parentTag]; - CGFloat value = [(RCTValueAnimatedNode *)parentNode value]; - self->_propsDictionary[property] = @(value); + id animatedObject = [(RCTValueAnimatedNode *)parentNode animatedObject]; + if (animatedObject) { + self->_propsDictionary[property] = animatedObject; + } else { + CGFloat value = [(RCTValueAnimatedNode *)parentNode value]; + self->_propsDictionary[property] = @(value); + } } } diff --git a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h index 53b5da3803e51f..c46d392caaac79 100644 --- a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h +++ b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h @@ -24,6 +24,7 @@ - (void)extractOffset; @property (nonatomic, assign) CGFloat value; +@property (nonatomic, strong) id animatedObject; @property (nonatomic, weak) id valueObserver; @end diff --git a/RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js b/RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js new file mode 100644 index 00000000000000..d69e91ded20659 --- /dev/null +++ b/RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js @@ -0,0 +1,103 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const React = require('react'); +const ReactNative = require('react-native'); +const {Component} = React; +const { + StyleSheet, + Text, + View, + Animated, + Easing, + TouchableOpacity, + Dimensions, +} = ReactNative; + +class ScrollViewAnimatedExample extends Component<{}> { + _scrollViewPos = new Animated.Value(0); + + startAnimation = () => { + this._scrollViewPos.setValue(0); + Animated.timing(this._scrollViewPos, { + toValue: 100, + duration: 10000, + easing: Easing.linear, + useNativeDriver: true, + }).start(); + }; + + render() { + const interpolated = this._scrollViewPos.interpolate({ + inputRange: [0, 1], + outputRange: [0, 0.1], + }); + const interpolated2 = this._scrollViewPos.interpolate({ + inputRange: [0, 1], + outputRange: ['0deg', '1deg'], + }); + return ( + + + + + + Scroll me horizontally + + + + + ); + } +} + +const {width, height} = Dimensions.get('window'); + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + button: { + margin: 50, + width: width, + marginRight: width, + height: height / 2, + }, +}); + +exports.title = ''; +exports.description = 'Component that is animated when ScrollView is offset.'; + +exports.examples = [ + { + title: 'Animated by scroll view', + render: function(): React.Element { + return ; + }, + }, +]; diff --git a/RNTester/js/utils/RNTesterList.android.js b/RNTester/js/utils/RNTesterList.android.js index 929d0b78cea949..31c0ffbbad83e7 100644 --- a/RNTester/js/utils/RNTesterList.android.js +++ b/RNTester/js/utils/RNTesterList.android.js @@ -65,6 +65,10 @@ const ComponentExamples: Array = [ key: 'ScrollViewSimpleExample', module: require('../examples/ScrollView/ScrollViewSimpleExample'), }, + { + key: 'ScrollViewAnimatedExample', + module: require('../examples/ScrollView/ScrollViewAnimatedExample'), + }, { key: 'SectionListExample', module: require('../examples/SectionList/SectionListExample'), diff --git a/RNTester/js/utils/RNTesterList.ios.js b/RNTester/js/utils/RNTesterList.ios.js index e5e4de716b544e..2dae203030a76f 100644 --- a/RNTester/js/utils/RNTesterList.ios.js +++ b/RNTester/js/utils/RNTesterList.ios.js @@ -113,6 +113,11 @@ const ComponentExamples: Array = [ module: require('../examples/ScrollView/ScrollViewExample'), supportsTVOS: true, }, + { + key: 'ScrollViewAnimatedExample', + module: require('../examples/ScrollView/ScrollViewAnimatedExample'), + supportsTVOS: true, + }, { key: 'SectionListExample', module: require('../examples/SectionList/SectionListExample'), diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java index be2f38c055de42..bc2e08c7adaad8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java @@ -9,6 +9,12 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableType; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import javax.annotation.Nullable; /** @@ -22,6 +28,9 @@ public static final String EXTRAPOLATE_TYPE_CLAMP = "clamp"; public static final String EXTRAPOLATE_TYPE_EXTEND = "extend"; + private static final String fpRegex = "[+-]?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?"; + private static final Pattern fpPattern = Pattern.compile(fpRegex); + private static double[] fromDoubleArray(ReadableArray ary) { double[] res = new double[ary.size()]; for (int i = 0; i < res.length; i++) { @@ -116,13 +125,68 @@ private static int findRangeIndex(double value, double[] ranges) { private final double mInputRange[]; private final double mOutputRange[]; + private String mPattern; + private double mOutputs[][]; + private final boolean mHasStringOutput; + private final Matcher mSOutputMatcher; private final String mExtrapolateLeft; private final String mExtrapolateRight; private @Nullable ValueAnimatedNode mParent; + private boolean mShouldRound; + private int mNumVals; public InterpolationAnimatedNode(ReadableMap config) { mInputRange = fromDoubleArray(config.getArray("inputRange")); - mOutputRange = fromDoubleArray(config.getArray("outputRange")); + ReadableArray output = config.getArray("outputRange"); + mHasStringOutput = output.getType(0) == ReadableType.String; + if (mHasStringOutput) { + /* + * Supports string shapes by extracting numbers so new values can be computed, + * and recombines those values into new strings of the same shape. Supports + * things like: + * + * rgba(123, 42, 99, 0.36) // colors + * -45deg // values with units + */ + int size = output.size(); + mOutputRange = new double[size]; + mPattern = output.getString(0); + mShouldRound = mPattern.startsWith("rgb"); + mSOutputMatcher = fpPattern.matcher(mPattern); + ArrayList> mOutputRanges = new ArrayList<>(); + for (int i = 0; i < size; i++) { + String val = output.getString(i); + Matcher m = fpPattern.matcher(val); + ArrayList outputRange = new ArrayList<>(); + mOutputRanges.add(outputRange); + while (m.find()) { + Double parsed = Double.parseDouble(m.group()); + outputRange.add(parsed); + } + mOutputRange[i] = outputRange.get(0); + } + + // ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)'] + // -> + // [ + // [0, 50], + // [100, 150], + // [200, 250], + // [0, 0.5], + // ] + mNumVals = mOutputRanges.get(0).size(); + mOutputs = new double[mNumVals][]; + for (int j = 0; j < mNumVals; j++) { + double[] arr = new double[size]; + mOutputs[j] = arr; + for (int i = 0; i < size; i++) { + arr[i] = mOutputRanges.get(i).get(j); + } + } + } else { + mOutputRange = fromDoubleArray(output); + mSOutputMatcher = null; + } mExtrapolateLeft = config.getString("extrapolateLeft"); mExtrapolateRight = config.getString("extrapolateRight"); } @@ -153,6 +217,36 @@ public void update() { // unattached node. return; } - mValue = interpolate(mParent.getValue(), mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight); + double value = mParent.getValue(); + mValue = interpolate(value, mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight); + if (mHasStringOutput) { + // 'rgba(0, 100, 200, 0)' + // -> + // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' + if (mNumVals > 1) { + StringBuffer sb = new StringBuffer(mPattern.length()); + int i = 0; + mSOutputMatcher.reset(); + while (mSOutputMatcher.find()) { + double val = interpolate(value, mInputRange, mOutputs[i++], mExtrapolateLeft, mExtrapolateRight); + if (mShouldRound) { + // rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to + // round the opacity (4th column). + boolean isAlpha = i == 4; + int rounded = (int)Math.round(isAlpha ? val * 1000 : val); + String num = isAlpha ? Double.toString((double)rounded / 1000) : Integer.toString(rounded); + mSOutputMatcher.appendReplacement(sb, num); + } else { + int intVal = (int)val; + String num = intVal != val ? Double.toString(val) : Integer.toString(intVal); + mSOutputMatcher.appendReplacement(sb, num); + } + } + mSOutputMatcher.appendTail(sb); + mAnimatedObject = sb.toString(); + } else { + mAnimatedObject = mSOutputMatcher.replaceFirst(String.valueOf(mValue)); + } + } } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java index 250eb21dbc0d9a..7bb7eaaeba2cd9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java @@ -84,7 +84,12 @@ public final void updateView() { } else if (node instanceof StyleAnimatedNode) { ((StyleAnimatedNode) node).collectViewUpdates(mPropMap); } else if (node instanceof ValueAnimatedNode) { - mPropMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue()); + Object animatedObject = ((ValueAnimatedNode) node).getAnimatedObject(); + if (animatedObject instanceof String) { + mPropMap.putString(entry.getKey(), (String)animatedObject); + } else { + mPropMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue()); + } } else { throw new IllegalArgumentException("Unsupported type of node used in property node " + node.getClass()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java index 49426c77ebb237..0c92f11f899362 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java @@ -16,6 +16,7 @@ * library. */ /*package*/ class ValueAnimatedNode extends AnimatedNode { + /*package*/ Object mAnimatedObject = null; /*package*/ double mValue = Double.NaN; /*package*/ double mOffset = 0; private @Nullable AnimatedNodeValueListener mValueListener; @@ -33,6 +34,10 @@ public double getValue() { return mOffset + mValue; } + public Object getAnimatedObject() { + return mAnimatedObject; + } + public void flattenOffset() { mValue += mOffset; mOffset = 0; From 63bc4b4aac0911086b9818e45dfb3ba5b6181bde Mon Sep 17 00:00:00 2001 From: Felix Oghina Date: Thu, 6 Jun 2019 04:49:51 -0700 Subject: [PATCH 120/330] @build-break Back out "[RN] Remove Map/Set from RN Open Source" Summary: Backing out D14786123 as it's causing failures on fbandroid/stable. Differential Revision: D15693250 Ninja: sheriff fbshipit-source-id: 526054d4f0dab2a811f2328540e7418ece9810b1 --- Libraries/Core/InitializeCore.js | 1 + .../Core/__tests__/MapAndSetPolyfills-test.js | 102 +++ Libraries/Core/polyfillES6Collections.js | 27 + Libraries/vendor/core/Map.js | 590 ++++++++++++++++++ Libraries/vendor/core/Set.js | 198 ++++++ .../core/_shouldPolyfillES6Collection.js | 66 ++ flow/Map.js | 40 ++ flow/Set.js | 36 ++ 8 files changed, 1060 insertions(+) create mode 100644 Libraries/Core/__tests__/MapAndSetPolyfills-test.js create mode 100644 Libraries/Core/polyfillES6Collections.js create mode 100644 Libraries/vendor/core/Map.js create mode 100644 Libraries/vendor/core/Set.js create mode 100644 Libraries/vendor/core/_shouldPolyfillES6Collection.js create mode 100644 flow/Map.js create mode 100644 flow/Set.js diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 8b9a6a490739d1..263001547b6132 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -28,6 +28,7 @@ const start = Date.now(); require('./setUpGlobals'); +require('./polyfillES6Collections'); require('./setUpSystrace'); require('./setUpErrorHandling'); require('./polyfillPromise'); diff --git a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js new file mode 100644 index 00000000000000..20f54a0e68d9d5 --- /dev/null +++ b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js @@ -0,0 +1,102 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @emails oncall+react_native + */ +'use strict'; + +// Save these methods so that we can restore them afterward. +const {freeze, seal, preventExtensions} = Object; + +function setup() { + jest.setMock('../../vendor/core/_shouldPolyfillES6Collection', () => true); +} + +function cleanup() { + Object.assign(Object, {freeze, seal, preventExtensions}); +} + +describe('Map polyfill', () => { + setup(); + + const Map = require('../../vendor/core/Map'); + + it('is not native', () => { + const getCode = Function.prototype.toString.call(Map.prototype.get); + expect(getCode).not.toContain('[native code]'); + expect(getCode).toContain('getIndex'); + }); + + it('should tolerate non-extensible object keys', () => { + const map = new Map(); + const key = Object.create(null); + Object.freeze(key); + map.set(key, key); + expect(map.size).toBe(1); + expect(map.has(key)).toBe(true); + map.delete(key); + expect(map.size).toBe(0); + expect(map.has(key)).toBe(false); + }); + + it('should not get confused by prototypal inheritance', () => { + const map = new Map(); + const proto = Object.create(null); + const base = Object.create(proto); + map.set(proto, proto); + expect(map.size).toBe(1); + expect(map.has(proto)).toBe(true); + expect(map.has(base)).toBe(false); + map.set(base, base); + expect(map.size).toBe(2); + expect(map.get(proto)).toBe(proto); + expect(map.get(base)).toBe(base); + }); + + afterAll(cleanup); +}); + +describe('Set polyfill', () => { + setup(); + + const Set = require('../../vendor/core/Set'); + + it('is not native', () => { + const addCode = Function.prototype.toString.call(Set.prototype.add); + expect(addCode).not.toContain('[native code]'); + }); + + it('should tolerate non-extensible object elements', () => { + const set = new Set(); + const elem = Object.create(null); + Object.freeze(elem); + set.add(elem); + expect(set.size).toBe(1); + expect(set.has(elem)).toBe(true); + set.add(elem); + expect(set.size).toBe(1); + set.delete(elem); + expect(set.size).toBe(0); + expect(set.has(elem)).toBe(false); + }); + + it('should not get confused by prototypal inheritance', () => { + const set = new Set(); + const proto = Object.create(null); + const base = Object.create(proto); + set.add(proto); + expect(set.size).toBe(1); + expect(set.has(proto)).toBe(true); + expect(set.has(base)).toBe(false); + set.add(base); + expect(set.size).toBe(2); + expect(set.has(proto)).toBe(true); + expect(set.has(base)).toBe(true); + }); + + afterAll(cleanup); +}); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js new file mode 100644 index 00000000000000..b58718540fedca --- /dev/null +++ b/Libraries/Core/polyfillES6Collections.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('../Utilities/PolyfillFunctions'); + +/** + * Polyfill ES6 collections (Map and Set). + * If you don't need these polyfills, don't use InitializeCore; just directly + * require the modules you need from InitializeCore for setup. + */ +const _shouldPolyfillCollection = require('../vendor/core/_shouldPolyfillES6Collection'); +if (_shouldPolyfillCollection('Map')) { + // $FlowFixMe: even in strict-local mode Flow expects Map to be Flow-typed + polyfillGlobal('Map', () => require('../vendor/core/Map')); +} +if (_shouldPolyfillCollection('Set')) { + // $FlowFixMe: even in strict-local mode Flow expects Set to be Flow-typed + polyfillGlobal('Set', () => require('../vendor/core/Set')); +} diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js new file mode 100644 index 00000000000000..4f23b1f4783ab8 --- /dev/null +++ b/Libraries/vendor/core/Map.js @@ -0,0 +1,590 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @preventMunge + * @typechecks + */ + +/* eslint-disable no-extend-native, no-shadow-restricted-names */ + +'use strict'; + +const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); +const guid = require('./guid'); +const toIterator = require('./toIterator'); + +module.exports = (function(global, undefined) { + // Since our implementation is spec-compliant for the most part we can safely + // delegate to a built-in version if exists and is implemented correctly. + // Firefox had gotten a few implementation details wrong across different + // versions so we guard against that. + if (!_shouldPolyfillES6Collection('Map')) { + return global.Map; + } + + const hasOwn = Object.prototype.hasOwnProperty; + + /** + * == ES6 Map Collection == + * + * This module is meant to implement a Map collection as described in chapter + * 23.1 of the ES6 specification. + * + * Map objects are collections of key/value pairs where both the keys and + * values may be arbitrary ECMAScript language values. A distinct key value + * may only occur in one key/value pair within the Map's collection. + * + * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects + * + * There only two -- rather small -- deviations from the spec: + * + * 1. The use of untagged frozen objects as keys. + * We decided not to allow and simply throw an error, because this + * implementation of Map works by tagging objects used as Map keys + * with a secret hash property for fast access to the object's place + * in the internal _mapData array. However, to limit the impact of + * this spec deviation, Libraries/Core/InitializeCore.js also wraps + * Object.freeze, Object.seal, and Object.preventExtensions so that + * they tag objects before making them non-extensible, by inserting + * each object into a Map and then immediately removing it. + * + * 2. The `size` property on a map object is a regular property and not a + * computed property on the prototype as described by the spec. + * The reason being is that we simply want to support ES3 environments + * which doesn't implement computed properties. + * + * == Usage == + * + * var map = new Map(iterable); + * + * map.set(key, value); + * map.get(key); // value + * map.has(key); // true + * map.delete(key); // true + * + * var iterator = map.keys(); + * iterator.next(); // {value: key, done: false} + * + * var iterator = map.values(); + * iterator.next(); // {value: value, done: false} + * + * var iterator = map.entries(); + * iterator.next(); // {value: [key, value], done: false} + * + * map.forEach(function(value, key){ this === thisArg }, thisArg); + * + * map.clear(); // resets map. + */ + + /** + * Constants + */ + + // Kinds of map iterations 23.1.5.3 + const KIND_KEY = 'key'; + const KIND_VALUE = 'value'; + const KIND_KEY_VALUE = 'key+value'; + + // In older browsers we can't create a null-prototype object so we have to + // defend against key collisions with built-in methods. + const KEY_PREFIX = '$map_'; + + // This property will be used as the internal size variable to disallow + // writing and to issue warnings for writings in development. + let SECRET_SIZE_PROP; + if (__DEV__) { + SECRET_SIZE_PROP = '$size' + guid(); + } + + class Map { + /** + * 23.1.1.1 + * Takes an `iterable` which is basically any object that implements a + * Symbol.iterator (@@iterator) method. The iterable is expected to be a + * collection of pairs. Each pair is a key/value pair that will be used + * to instantiate the map. + * + * @param {*} iterable + */ + constructor(iterable) { + if (!isObject(this)) { + throw new TypeError('Wrong map object type.'); + } + + initMap(this); + + if (iterable != null) { + const it = toIterator(iterable); + let next; + while (!(next = it.next()).done) { + if (!isObject(next.value)) { + throw new TypeError('Expected iterable items to be pair objects.'); + } + this.set(next.value[0], next.value[1]); + } + } + } + + /** + * 23.1.3.1 + * Clears the map from all keys and values. + */ + clear() { + initMap(this); + } + + /** + * 23.1.3.7 + * Check if a key exists in the collection. + * + * @param {*} key + * @return {boolean} + */ + has(key) { + const index = getIndex(this, key); + return !!(index != null && this._mapData[index]); + } + + /** + * 23.1.3.9 + * Adds a key/value pair to the collection. + * + * @param {*} key + * @param {*} value + * @return {map} + */ + set(key, value) { + let index = getIndex(this, key); + + if (index != null && this._mapData[index]) { + this._mapData[index][1] = value; + } else { + index = this._mapData.push([key, value]) - 1; + setIndex(this, key, index); + if (__DEV__) { + this[SECRET_SIZE_PROP] += 1; + } else { + this.size += 1; + } + } + + return this; + } + + /** + * 23.1.3.6 + * Gets a value associated with a key in the collection. + * + * @param {*} key + * @return {*} + */ + get(key) { + const index = getIndex(this, key); + if (index == null) { + return undefined; + } else { + return this._mapData[index][1]; + } + } + + /** + * 23.1.3.3 + * Delete a key/value from the collection. + * + * @param {*} key + * @return {boolean} Whether the key was found and deleted. + */ + delete(key) { + const index = getIndex(this, key); + if (index != null && this._mapData[index]) { + setIndex(this, key, undefined); + this._mapData[index] = undefined; + if (__DEV__) { + this[SECRET_SIZE_PROP] -= 1; + } else { + this.size -= 1; + } + return true; + } else { + return false; + } + } + + /** + * 23.1.3.4 + * Returns an iterator over the key/value pairs (in the form of an Array) in + * the collection. + * + * @return {MapIterator} + */ + entries() { + return new MapIterator(this, KIND_KEY_VALUE); + } + + /** + * 23.1.3.8 + * Returns an iterator over the keys in the collection. + * + * @return {MapIterator} + */ + keys() { + return new MapIterator(this, KIND_KEY); + } + + /** + * 23.1.3.11 + * Returns an iterator over the values pairs in the collection. + * + * @return {MapIterator} + */ + values() { + return new MapIterator(this, KIND_VALUE); + } + + /** + * 23.1.3.5 + * Iterates over the key/value pairs in the collection calling `callback` + * with [value, key, map]. An optional `thisArg` can be passed to set the + * context when `callback` is called. + * + * @param {function} callback + * @param {?object} thisArg + */ + forEach(callback, thisArg) { + if (typeof callback !== 'function') { + throw new TypeError('Callback must be callable.'); + } + + const boundCallback = callback.bind(thisArg || undefined); + const mapData = this._mapData; + + // Note that `mapData.length` should be computed on each iteration to + // support iterating over new items in the map that were added after the + // start of the iteration. + for (let i = 0; i < mapData.length; i++) { + const entry = mapData[i]; + if (entry != null) { + boundCallback(entry[1], entry[0], this); + } + } + } + } + + // 23.1.3.12 + Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries; + + class MapIterator { + /** + * 23.1.5.1 + * Create a `MapIterator` for a given `map`. While this class is private it + * will create objects that will be passed around publicily. + * + * @param {map} map + * @param {string} kind + */ + constructor(map, kind) { + if (!(isObject(map) && map._mapData)) { + throw new TypeError('Object is not a map.'); + } + + if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) { + throw new Error('Invalid iteration kind.'); + } + + this._map = map; + this._nextIndex = 0; + this._kind = kind; + } + + /** + * 23.1.5.2.1 + * Get the next iteration. + * + * @return {object} + */ + next() { + if (!this instanceof Map) { + throw new TypeError('Expected to be called on a MapIterator.'); + } + + const map = this._map; + let index = this._nextIndex; + const kind = this._kind; + + if (map == null) { + return createIterResultObject(undefined, true); + } + + const entries = map._mapData; + + while (index < entries.length) { + const record = entries[index]; + + index += 1; + this._nextIndex = index; + + if (record) { + if (kind === KIND_KEY) { + return createIterResultObject(record[0], false); + } else if (kind === KIND_VALUE) { + return createIterResultObject(record[1], false); + } else if (kind) { + return createIterResultObject(record, false); + } + } + } + + this._map = undefined; + + return createIterResultObject(undefined, true); + } + } + + // We can put this in the class definition once we have computed props + // transform. + // 23.1.5.2.2 + MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() { + return this; + }; + + /** + * Helper Functions. + */ + + /** + * Return an index to map.[[MapData]] array for a given Key. + * + * @param {map} map + * @param {*} key + * @return {?number} + */ + function getIndex(map, key) { + if (isObject(key)) { + const hash = getHash(key); + return map._objectIndex[hash]; + } else { + const prefixedKey = KEY_PREFIX + key; + if (typeof key === 'string') { + return map._stringIndex[prefixedKey]; + } else { + return map._otherIndex[prefixedKey]; + } + } + } + + /** + * Setup an index that refer to the key's location in map.[[MapData]]. + * + * @param {map} map + * @param {*} key + */ + function setIndex(map, key, index) { + const shouldDelete = index == null; + + if (isObject(key)) { + const hash = getHash(key); + if (shouldDelete) { + delete map._objectIndex[hash]; + } else { + map._objectIndex[hash] = index; + } + } else { + const prefixedKey = KEY_PREFIX + key; + if (typeof key === 'string') { + if (shouldDelete) { + delete map._stringIndex[prefixedKey]; + } else { + map._stringIndex[prefixedKey] = index; + } + } else { + if (shouldDelete) { + delete map._otherIndex[prefixedKey]; + } else { + map._otherIndex[prefixedKey] = index; + } + } + } + } + + /** + * Instantiate a map with internal slots. + * + * @param {map} map + */ + function initMap(map) { + // Data structure design inspired by Traceur's Map implementation. + // We maintain an internal array for all the entries. The array is needed + // to remember order. However, to have a reasonable HashMap performance + // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices + // in objects for fast look ups. Indices are split up according to data + // types to avoid collisions. + map._mapData = []; + + // Object index maps from an object "hash" to index. The hash being a unique + // property of our choosing that we associate with the object. Association + // is done by ways of keeping a non-enumerable property on the object. + // Ideally these would be `Object.create(null)` objects but since we're + // trying to support ES3 we'll have to guard against collisions using + // prefixes on the keys rather than rely on null prototype objects. + map._objectIndex = {}; + + // String index maps from strings to index. + map._stringIndex = {}; + + // Numbers, booleans, undefined, and null. + map._otherIndex = {}; + + // Unfortunately we have to support ES3 and cannot have `Map.prototype.size` + // be a getter method but just a regular method. The biggest problem with + // this is safety. Clients can change the size property easily and possibly + // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we + // can do to mitigate use getters and setters in development to disallow + // and issue a warning for changing the `size` property. + if (__DEV__) { + if (isES5) { + // If the `SECRET_SIZE_PROP` property is already defined then we're not + // in the first call to `initMap` (e.g. coming from `map.clear()`) so + // all we need to do is reset the size without defining the properties. + if (hasOwn.call(map, SECRET_SIZE_PROP)) { + map[SECRET_SIZE_PROP] = 0; + } else { + Object.defineProperty(map, SECRET_SIZE_PROP, { + value: 0, + writable: true, + }); + Object.defineProperty(map, 'size', { + set: v => { + console.error( + 'PLEASE FIX ME: You are changing the map size property which ' + + 'should not be writable and will break in production.', + ); + throw new Error('The map size property is not writable.'); + }, + get: () => map[SECRET_SIZE_PROP], + }); + } + + // NOTE: Early return to implement immutable `.size` in DEV. + return; + } + } + + // This is a diviation from the spec. `size` should be a getter on + // `Map.prototype`. However, we have to support IE8. + map.size = 0; + } + + /** + * Check if something is an object. + * + * @param {*} o + * @return {boolean} + */ + function isObject(o) { + return o != null && (typeof o === 'object' || typeof o === 'function'); + } + + /** + * Create an iteration object. + * + * @param {*} value + * @param {boolean} done + * @return {object} + */ + function createIterResultObject(value, done) { + return {value, done}; + } + + // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8. + const isES5 = (function() { + try { + Object.defineProperty({}, 'x', {}); + return true; + } catch (e) { + return false; + } + })(); + + /** + * Check if an object can be extended. + * + * @param {object|array|function|regexp} o + * @return {boolean} + */ + function isExtensible(o) { + if (!isES5) { + return true; + } else { + return Object.isExtensible(o); + } + } + + const getHash = (function() { + const propIsEnumerable = Object.prototype.propertyIsEnumerable; + const hashProperty = '__MAP_POLYFILL_INTERNAL_HASH__'; + let hashCounter = 0; + + const nonExtensibleObjects = []; + const nonExtensibleHashes = []; + + /** + * Get the "hash" associated with an object. + * + * @param {object|array|function|regexp} o + * @return {number} + */ + return function getHash(o) { + if (hasOwn.call(o, hashProperty)) { + return o[hashProperty]; + } + + if (!isES5) { + if ( + hasOwn.call(o, 'propertyIsEnumerable') && + hasOwn.call(o.propertyIsEnumerable, hashProperty) + ) { + return o.propertyIsEnumerable[hashProperty]; + } + } + + if (isExtensible(o)) { + if (isES5) { + Object.defineProperty(o, hashProperty, { + enumerable: false, + writable: false, + configurable: false, + value: ++hashCounter, + }); + return hashCounter; + } + + if (o.propertyIsEnumerable) { + // Since we can't define a non-enumerable property on the object + // we'll hijack one of the less-used non-enumerable properties to + // save our hash on it. Additionally, since this is a function it + // will not show up in `JSON.stringify` which is what we want. + o.propertyIsEnumerable = function() { + return propIsEnumerable.apply(this, arguments); + }; + return (o.propertyIsEnumerable[hashProperty] = ++hashCounter); + } + } + + // If the object is not extensible, fall back to storing it in an + // array and using Array.prototype.indexOf to find it. + let index = nonExtensibleObjects.indexOf(o); + if (index < 0) { + index = nonExtensibleObjects.length; + nonExtensibleObjects[index] = o; + nonExtensibleHashes[index] = ++hashCounter; + } + return nonExtensibleHashes[index]; + }; + })(); + + return Map; +})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js new file mode 100644 index 00000000000000..564f530b9afd8a --- /dev/null +++ b/Libraries/vendor/core/Set.js @@ -0,0 +1,198 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @preventMunge + * @typechecks + */ + +/* eslint-disable no-extend-native */ + +'use strict'; + +const Map = require('./Map'); + +const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); +const toIterator = require('./toIterator'); + +module.exports = (function(global) { + // Since our implementation is spec-compliant for the most part we can safely + // delegate to a built-in version if exists and is implemented correctly. + // Firefox had gotten a few implementation details wrong across different + // versions so we guard against that. + // These checks are adapted from es6-shim https://fburl.com/34437854 + if (!_shouldPolyfillES6Collection('Set')) { + return global.Set; + } + + /** + * == ES6 Set Collection == + * + * This module is meant to implement a Set collection as described in chapter + * 23.2 of the ES6 specification. + * + * Set objects are collections of unique values. Where values can be any + * JavaScript value. + * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects + * + * There only two -- rather small -- diviations from the spec: + * + * 1. The use of frozen objects as keys. @see Map module for more on this. + * + * 2. The `size` property on a map object is a regular property and not a + * computed property on the prototype as described by the spec. + * The reason being is that we simply want to support ES3 environments + * which doesn't implement computed properties. + * + * == Usage == + * + * var set = new set(iterable); + * + * set.set(value); + * set.has(value); // true + * set.delete(value); // true + * + * var iterator = set.keys(); + * iterator.next(); // {value: value, done: false} + * + * var iterator = set.values(); + * iterator.next(); // {value: value, done: false} + * + * var iterator = set.entries(); + * iterator.next(); // {value: [value, value], done: false} + * + * set.forEach(function(value, value){ this === thisArg }, thisArg); + * + * set.clear(); // resets set. + */ + + class Set { + /** + * 23.2.1.1 + * + * Takes an optional `iterable` (which is basically any object that + * implements a Symbol.iterator (@@iterator) method). That is a collection + * of values used to instantiate the set. + * + * @param {*} iterable + */ + constructor(iterable) { + if ( + this == null || + (typeof this !== 'object' && typeof this !== 'function') + ) { + throw new TypeError('Wrong set object type.'); + } + + initSet(this); + + if (iterable != null) { + const it = toIterator(iterable); + let next; + while (!(next = it.next()).done) { + this.add(next.value); + } + } + } + + /** + * 23.2.3.1 + * + * If it doesn't already exist in the collection a `value` is added. + * + * @param {*} value + * @return {set} + */ + add(value) { + this._map.set(value, value); + this.size = this._map.size; + return this; + } + + /** + * 23.2.3.2 + * + * Clears the set. + */ + clear() { + initSet(this); + } + + /** + * 23.2.3.4 + * + * Deletes a `value` from the collection if it exists. + * Returns true if the value was found and deleted and false otherwise. + * + * @param {*} value + * @return {boolean} + */ + delete(value) { + const ret = this._map.delete(value); + this.size = this._map.size; + return ret; + } + + /** + * 23.2.3.5 + * + * Returns an iterator over a collection of [value, value] tuples. + */ + entries() { + return this._map.entries(); + } + + /** + * 23.2.3.6 + * + * Iterate over the collection calling `callback` with (value, value, set). + * + * @param {function} callback + */ + forEach(callback) { + const thisArg = arguments[1]; + const it = this._map.keys(); + let next; + while (!(next = it.next()).done) { + callback.call(thisArg, next.value, next.value, this); + } + } + + /** + * 23.2.3.7 + * + * Iterate over the collection calling `callback` with (value, value, set). + * + * @param {*} value + * @return {boolean} + */ + has(value) { + return this._map.has(value); + } + + /** + * 23.2.3.7 + * + * Returns an iterator over the colleciton of values. + */ + values() { + return this._map.values(); + } + } + + // 23.2.3.11 + Set.prototype[toIterator.ITERATOR_SYMBOL] = Set.prototype.values; + + // 23.2.3.7 + Set.prototype.keys = Set.prototype.values; + + function initSet(set) { + set._map = new Map(); + set.size = set._map.size; + } + + return Set; +})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js new file mode 100644 index 00000000000000..1ba893c5aebdbe --- /dev/null +++ b/Libraries/vendor/core/_shouldPolyfillES6Collection.js @@ -0,0 +1,66 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @preventMunge + * @flow strict + */ + +'use strict'; + +/** + * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill + * that is safe to be used. + */ +function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { + const Collection = global[collectionName]; + if (Collection == null) { + return true; + } + + // The iterator protocol depends on `Symbol.iterator`. If a collection is + // implemented, but `Symbol` is not, it's going to break iteration because + // we'll be using custom "@@iterator" instead, which is not implemented on + // native collections. + if (typeof global.Symbol !== 'function') { + return true; + } + + const proto = Collection.prototype; + + // These checks are adapted from es6-shim: https://fburl.com/34437854 + // NOTE: `isCallableWithoutNew` and `!supportsSubclassing` are not checked + // because they make debugging with "break on exceptions" difficult. + return ( + Collection == null || + typeof Collection !== 'function' || + typeof proto.clear !== 'function' || + new Collection().size !== 0 || + typeof proto.keys !== 'function' || + typeof proto.forEach !== 'function' + ); +} + +const cache: {[name: string]: boolean} = {}; + +/** + * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill + * that is safe to be used and caches this result. + * Make sure to make a first call to this function before a corresponding + * property on global was overriden in any way. + */ +function _shouldPolyfillES6Collection(collectionName: string) { + let result = cache[collectionName]; + if (result !== undefined) { + return result; + } + + result = _shouldActuallyPolyfillES6Collection(collectionName); + cache[collectionName] = result; + return result; +} + +module.exports = _shouldPolyfillES6Collection; diff --git a/flow/Map.js b/flow/Map.js new file mode 100644 index 00000000000000..c8e830529798ff --- /dev/null +++ b/flow/Map.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + * @format + */ + +// These annotations are copy/pasted from the built-in Flow definitions for +// Native Map. + +declare module 'Map' { + // Use the name "MapPolyfill" so that we don't get confusing error + // messages about "Using Map instead of Map". + declare class MapPolyfill { + @@iterator(): Iterator<[K, V]>; + constructor(_: void): MapPolyfill; + constructor(_: null): MapPolyfill; + constructor( + iterable: Iterable<[Key, Value]>, + ): MapPolyfill; + clear(): void; + delete(key: K): boolean; + entries(): Iterator<[K, V]>; + forEach( + callbackfn: (value: V, index: K, map: MapPolyfill) => mixed, + thisArg?: any, + ): void; + get(key: K): V | void; + has(key: K): boolean; + keys(): Iterator; + set(key: K, value: V): MapPolyfill; + size: number; + values(): Iterator; + } + + declare module.exports: typeof MapPolyfill; +} diff --git a/flow/Set.js b/flow/Set.js new file mode 100644 index 00000000000000..64099c2a6028c3 --- /dev/null +++ b/flow/Set.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + * @nolint + * @format + */ + +// These annotations are copy/pasted from the built-in Flow definitions for +// Native Set. + +declare module 'Set' { + // Use the name "SetPolyfill" so that we don't get confusing error + // messages about "Using Set instead of Set". + declare class SetPolyfill { + @@iterator(): Iterator; + constructor(iterable: ?Iterable): void; + add(value: T): SetPolyfill; + clear(): void; + delete(value: T): boolean; + entries(): Iterator<[T, T]>; + forEach( + callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, + thisArg?: any, + ): void; + has(value: T): boolean; + keys(): Iterator; + size: number; + values(): Iterator; + } + + declare module.exports: typeof SetPolyfill; +} From 9b61896f406cfe80fe2941bd846cc5cdbbeab238 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 6 Jun 2019 09:13:52 -0700 Subject: [PATCH 121/330] Don't apply empty attributed string for TextInput (#25143) Summary: Issue reported by Titozzz , `TextInput` would shrink when we have attributes like `lineHeight`. Demonstration can see GIF like below: https://giphy.com/gifs/KGNs1qIMHF3DIk1EPK I think the reason is we apply an empty attributed string to `UITextField`, now if the length is 0, we just nil the `attributedText` instead. ## Changelog [iOS] [Fixed] - Don't apply empty attributed string for TextInput Pull Request resolved: https://github.com/facebook/react-native/pull/25143 Differential Revision: D15661751 Pulled By: sammy-SC fbshipit-source-id: 9770484a1b68a6409e63ea25ac9a6fd0d3589b14 --- Libraries/Text/TextInput/RCTBaseTextInputShadowView.m | 7 ++++++- Libraries/Text/TextInput/RCTBaseTextInputView.h | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m index c79d65e136f88f..c6cc08bb8bf0f3 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m @@ -174,7 +174,12 @@ - (void)uiManagerWillPerformMounting baseTextInputView.reactPaddingInsets = paddingInsets; if (isAttributedTextChanged) { - baseTextInputView.attributedText = attributedText; + // Don't set `attributedText` if length equal to zero, otherwise it would shrink when attributes contain like `lineHeight`. + if (attributedText.length != 0) { + baseTextInputView.attributedText = attributedText; + } else { + baseTextInputView.attributedText = nil; + } } }]; } diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.h b/Libraries/Text/TextInput/RCTBaseTextInputView.h index 5b62f90251492e..ead709672f8f9a 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.h +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.h @@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL secureTextEntry; @property (nonatomic, copy) RCTTextSelection *selection; @property (nonatomic, strong, nullable) NSNumber *maxLength; -@property (nonatomic, copy) NSAttributedString *attributedText; +@property (nonatomic, copy, nullable) NSAttributedString *attributedText; @property (nonatomic, copy) NSString *inputAccessoryViewID; @property (nonatomic, assign) UIKeyboardType keyboardType; From 360e999937dc1d15d7b67f3fde5f3dde448e23cd Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 6 Jun 2019 09:35:16 -0700 Subject: [PATCH 122/330] TM iOS: reduce the scope of cache access lock Summary: We just need to protect access to the cache, we don't need to protect the entire module lookup, because a module initialization may try to lookup another module, causing deadlocks. Reviewed By: RSNara Differential Revision: D15690645 fbshipit-source-id: cbb780db8699a94f2c9a2e121b35ddad2b125b65 --- .../platform/ios/RCTTurboModuleManager.mm | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 93f91f00ef7769..91fdbc9b329efd 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -211,37 +211,46 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name */ - (id)provideRCTTurboModule:(const char *)moduleName { - std::lock_guard guard{_rctTurboModuleCacheLock}; + Class moduleClass; + id module = nil; - auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName); - if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) { - return rctTurboModuleCacheLookup->second; - } + { + std::unique_lock lock(_rctTurboModuleCacheLock); - /** - * Step 2a: Resolve platform-specific class. - */ - Class moduleClass; - if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) { - moduleClass = [_delegate getModuleClassFromName:moduleName]; - } + auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName); + if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) { + return rctTurboModuleCacheLookup->second; + } - if (!moduleClass) { - moduleClass = getFallbackClassFromName(moduleName); - } + /** + * Step 2a: Resolve platform-specific class. + */ + if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) { + moduleClass = [_delegate getModuleClassFromName:moduleName]; + } - if (![moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) { - return nil; - } + if (!moduleClass) { + moduleClass = getFallbackClassFromName(moduleName); + } - /** - * Step 2b: Ask hosting application/delegate to instantiate this class - */ - id module = nil; - if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) { - module = [_delegate getModuleInstanceFromClass:moduleClass]; - } else { - module = [moduleClass new]; + if (![moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) { + return nil; + } + + /** + * Step 2b: Ask hosting application/delegate to instantiate this class + */ + if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) { + module = [_delegate getModuleInstanceFromClass:moduleClass]; + } else { + module = [moduleClass new]; + } + + if ([module respondsToSelector:@selector(setTurboModuleLookupDelegate:)]) { + [module setTurboModuleLookupDelegate:self]; + } + + _rctTurboModuleCache.insert({moduleName, module}); } /** @@ -280,12 +289,6 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name } } - if ([module respondsToSelector:@selector(setTurboModuleLookupDelegate:)]) { - [module setTurboModuleLookupDelegate:self]; - } - - _rctTurboModuleCache.insert({moduleName, module}); - /** * Broadcast that this TurboModule was created. * @@ -336,6 +339,7 @@ - (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLoo - (BOOL)moduleIsInitialized:(const char *)moduleName { + std::unique_lock lock(_rctTurboModuleCacheLock); return _rctTurboModuleCache.find(std::string(moduleName)) != _rctTurboModuleCache.end(); } From 2fe3dd2e7d27789918079c66636c5161e22c5c33 Mon Sep 17 00:00:00 2001 From: Arthur Lee Date: Thu, 6 Jun 2019 11:30:19 -0700 Subject: [PATCH 123/330] Use fetch as a polyfill Summary: The old whatwg-fetch module doesn't actually export anything, so we would always hit the `else` condition. The new whatwg-fetch (3.0.0, introduced in #24418) now exports an ES module. As a result, `whatwg` and `whatwg.fetch` are both truthy but the `module.exports` will end up empty. This breaks the RN fetch module. This will switch the behavior back to the expected polyfill behavior (calling `require('whatwg-fetch')` and allowing it to polyfill fetch in global scope). The RN fetch module will re-export these globals. Reviewed By: cpojer Differential Revision: D15639851 fbshipit-source-id: ebd8bce85f7797d8539f53982e515ac47f6425e7 --- Libraries/Network/fetch.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Libraries/Network/fetch.js b/Libraries/Network/fetch.js index 66687e70de2035..65a02b9ee4d428 100644 --- a/Libraries/Network/fetch.js +++ b/Libraries/Network/fetch.js @@ -11,10 +11,8 @@ 'use strict'; -const whatwg = require('whatwg-fetch'); +// side-effectful require() to put fetch, +// Headers, Request, Response in global scope +require('whatwg-fetch'); -if (whatwg && whatwg.fetch) { - module.exports = whatwg; -} else { - module.exports = {fetch, Headers, Request, Response}; -} +module.exports = {fetch, Headers, Request, Response}; From ac7ec4602fd4d8ec033a084df6a92437ea2d3a8a Mon Sep 17 00:00:00 2001 From: Joshua Ong Date: Thu, 6 Jun 2019 11:54:08 -0700 Subject: [PATCH 124/330] Allow headless JS tasks to retry (#23231) Summary: `setTimeout` inside a headless JS task does not always works; the function does not get invoked until the user starts an `Activity`. This was attempted to be used in the context of widgets. When the widget update or user interaction causes the process and React context to be created, the headless JS task may run before other app-specific JS initialisation logic has completed. If it's not possible to change the behaviour of the pre-requisites to be synchronous, then the headless JS task blocks such asynchronous JS work that it may depend on. A primitive solution is the use of `setTimeout` in order to wait for the pre-conditions to be met before continuing with the rest of the headless JS task. But as the function passed to `setTimeout` is not always called, the task will not run to completion. This PR solves this scenario by allowing the task to be retried again with a delay. If the task returns a promise that resolves to a `{'timeout': number}` object, `AppRegistry.js` will not notify that the task has finished as per master, instead it will tell `HeadlessJsContext` to `startTask` again (cleaning up any posted `Runnable`s beforehand) via a `Handler` within the `HeadlessJsContext`. Documentation also updated here: https://github.com/facebook/react-native-website/pull/771 ### AppRegistry.js If the task provider does not return any data, or if the data it returns does not contain `timeout` as a number, then it behaves as `master`; notifies that the task has finished. If the response does contain `{timeout: number}`, then it will attempt to queue a retry. If that fails, then it will behaves as if the task provider returned no response i.e. behaves as `master` again. If the retry was successfully queued, then there is nothing to do as we do not want the `Service` to stop itself. ### HeadlessJsTaskSupportModule.java Similar to notify start/finished, we simply check if the context is running, and if so, pass the request onto `HeadlessJsTaskContext`. The only difference here is that we return a `Promise`, so that `AppRegistry`, as above, knows whether the enqueuing failed and thus needs to perform the usual task clean-up. ### HeadlessJsTaskContext.java Before retrying, we need to clean-up any timeout `Runnable`'s posted for the first attempt. Then we need to copy the task config so that if this retry (second attempt) also fails, then on the third attempt (second retry) we do not run into a consumed exception. This is also why in `startTask` we copy the config before putting it in the `Map`, so that the initial attempt does leave the config's in the map as consumed. Then we post a `Runnable` to call `startTask` on the main thread's `Handler`. We use the same `taskId` because the `Service` is keeping track of active task IDs in order to calculate whether it needs to `stopSelf`. This negates the need to inform the `Service` of a new task id and us having to remove the old one. ## Changelog [Android][added] - Allow headless JS tasks to return a promise that will cause the task to be retried again with the specified delay Pull Request resolved: https://github.com/facebook/react-native/pull/23231 Differential Revision: D15646870 fbshipit-source-id: 4440f4b4392f1fa5c69aab7908b51b7007ba2c40 --- Libraries/ReactNative/AppRegistry.js | 15 +++- Libraries/ReactNative/HeadlessJsTaskError.js | 12 +++ .../NativeHeadlessJsTaskSupport.js | 1 + .../tests/core/WritableNativeMapTest.java | 26 +++++- .../facebook/react/bridge/JavaOnlyMap.java | 7 ++ .../facebook/react/bridge/UiThreadUtil.java | 9 +- .../facebook/react/bridge/WritableMap.java | 1 + .../react/bridge/WritableNativeMap.java | 7 ++ .../react/jstasks/HeadlessJsTaskConfig.java | 46 ++++++++++ .../react/jstasks/HeadlessJsTaskContext.java | 83 ++++++++++++++++--- .../jstasks/HeadlessJsTaskRetryPolicy.java | 16 ++++ .../jstasks/LinearCountingRetryPolicy.java | 38 +++++++++ .../facebook/react/jstasks/NoRetryPolicy.java | 30 +++++++ .../core/HeadlessJsTaskSupportModule.java | 17 ++++ 14 files changed, 290 insertions(+), 18 deletions(-) create mode 100644 Libraries/ReactNative/HeadlessJsTaskError.js create mode 100644 ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 2d517ce6dd0f10..d7e9fc788a8adb 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -21,6 +21,7 @@ const createPerformanceLogger = require('../Utilities/createPerformanceLogger'); import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger'; import NativeHeadlessJsTaskSupport from './NativeHeadlessJsTaskSupport'; +import HeadlessJsTaskError from './HeadlessJsTaskError'; type Task = (taskData: any) => Promise; type TaskProvider = () => Task; @@ -275,8 +276,18 @@ const AppRegistry = { }) .catch(reason => { console.error(reason); - if (NativeHeadlessJsTaskSupport) { - NativeHeadlessJsTaskSupport.notifyTaskFinished(taskId); + + if ( + NativeHeadlessJsTaskSupport && + reason instanceof HeadlessJsTaskError + ) { + NativeHeadlessJsTaskSupport.notifyTaskRetry(taskId).then( + retryPosted => { + if (!retryPosted) { + NativeHeadlessJsTaskSupport.notifyTaskFinished(taskId); + } + }, + ); } }); }, diff --git a/Libraries/ReactNative/HeadlessJsTaskError.js b/Libraries/ReactNative/HeadlessJsTaskError.js new file mode 100644 index 00000000000000..0f85e138bb5a5f --- /dev/null +++ b/Libraries/ReactNative/HeadlessJsTaskError.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ +'use strict'; + +export default class HeadlessJsTaskError extends Error {} diff --git a/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js index 686ababaa9ae4f..d3256f49e10046 100644 --- a/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js +++ b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js @@ -15,6 +15,7 @@ import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +notifyTaskFinished: (taskId: number) => void; + +notifyTaskRetry: (taskId: number) => Promise; } export default TurboModuleRegistry.get('HeadlessJsTaskSupport'); diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java index 5199156393d99e..e709799f66e7dd 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java @@ -5,6 +5,8 @@ import androidx.test.runner.AndroidJUnit4; import com.facebook.react.bridge.NoSuchKeyException; import com.facebook.react.bridge.UnexpectedNativeTypeException; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; import org.junit.Assert; @@ -16,6 +18,8 @@ @RunWith(AndroidJUnit4.class) public class WritableNativeMapTest { + private static final String ARRAY = "array"; + private static final String MAP = "map"; private WritableNativeMap mMap; @Before @@ -25,8 +29,8 @@ public void setup() { mMap.putDouble("double", 1.2); mMap.putInt("int", 1); mMap.putString("string", "abc"); - mMap.putMap("map", new WritableNativeMap()); - mMap.putArray("array", new WritableNativeArray()); + mMap.putMap(MAP, new WritableNativeMap()); + mMap.putArray(ARRAY, new WritableNativeArray()); mMap.putBoolean("dvacca", true); } @@ -100,4 +104,22 @@ public void testErrorMessageContainsKey() { assertThat(e.getMessage()).contains(key); } } + + @Test + public void testCopy() { + final WritableMap copy = mMap.copy(); + + assertThat(copy).isNotSameAs(mMap); + assertThat(copy.getMap(MAP)).isNotSameAs(mMap.getMap(MAP)); + assertThat(copy.getArray(ARRAY)).isNotSameAs(mMap.getArray(ARRAY)); + } + + @Test + public void testCopyModification() { + final WritableMap copy = mMap.copy(); + copy.putString("string", "foo"); + + assertThat(copy.getString("string")).isEqualTo("foo"); + assertThat(mMap.getString("string")).isEqualTo("abc"); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java index 139f824611338a..ddf450f814ccfb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java @@ -206,6 +206,13 @@ public void merge(@Nonnull ReadableMap source) { mBackingMap.putAll(((JavaOnlyMap) source).mBackingMap); } + @Override + public WritableMap copy() { + final JavaOnlyMap target = new JavaOnlyMap(); + target.merge(this); + return target; + } + @Override public void putArray(@Nonnull String key, @Nullable WritableArray value) { mBackingMap.put(key, value); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java index 3adf9b8359e6f3..9b320097d69e56 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java @@ -44,11 +44,18 @@ public static void assertNotOnUiThread() { * Runs the given {@code Runnable} on the UI thread. */ public static void runOnUiThread(Runnable runnable) { + runOnUiThread(runnable, 0); + } + + /** + * Runs the given {@code Runnable} on the UI thread with the specified delay. + */ + public static void runOnUiThread(Runnable runnable, long delayInMs) { synchronized (UiThreadUtil.class) { if (sMainHandler == null) { sMainHandler = new Handler(Looper.getMainLooper()); } } - sMainHandler.post(runnable); + sMainHandler.postDelayed(runnable, delayInMs); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java index 1aa2d7a108f683..9338c19ae96903 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java @@ -24,4 +24,5 @@ public interface WritableMap extends ReadableMap { void putMap(@Nonnull String key, @Nullable WritableMap value); void merge(@Nonnull ReadableMap source); + WritableMap copy(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java index ec632940b47e86..997f4058783336 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java @@ -61,6 +61,13 @@ public void merge(@Nonnull ReadableMap source) { mergeNativeMap((ReadableNativeMap) source); } + @Override + public WritableMap copy() { + final WritableNativeMap target = new WritableNativeMap(); + target.merge(this); + return target; + } + public WritableNativeMap() { super(initHybrid()); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java index f0e15451f7cd7e..1c441300ba1a40 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java @@ -15,6 +15,7 @@ public class HeadlessJsTaskConfig { private final WritableMap mData; private final long mTimeout; private final boolean mAllowedInForeground; + private final HeadlessJsTaskRetryPolicy mRetryPolicy; /** * Create a HeadlessJsTaskConfig. Equivalent to calling @@ -55,10 +56,51 @@ public HeadlessJsTaskConfig( WritableMap data, long timeout, boolean allowedInForeground) { + this(taskKey, data, timeout, allowedInForeground, NoRetryPolicy.INSTANCE); + } + + /** + * Create a HeadlessJsTaskConfig. + * + * @param taskKey the key for the JS task to execute. This is the same key that you call {@code + * AppRegistry.registerTask} with in JS. + * @param data a map of parameters passed to the JS task executor. + * @param timeout the amount of time (in ms) after which the React instance should be terminated + * regardless of whether the task has completed or not. This is meant as a safeguard against + * accidentally keeping the device awake for long periods of time because JS crashed or some + * request timed out. A value of 0 means no timeout (should only be used for long-running tasks + * such as music playback). + * @param allowedInForeground whether to allow this task to run while the app is in the foreground + * (i.e. there is a host in resumed mode for the current ReactContext). Only set this to true if + * you really need it. Note that tasks run in the same JS thread as UI code, so doing expensive + * operations would degrade user experience. + * @param retryPolicy the number of times & delays the task should be retried on error. + */ + public HeadlessJsTaskConfig( + String taskKey, + WritableMap data, + long timeout, + boolean allowedInForeground, + HeadlessJsTaskRetryPolicy retryPolicy) { mTaskKey = taskKey; mData = data; mTimeout = timeout; mAllowedInForeground = allowedInForeground; + mRetryPolicy = retryPolicy; + } + + public HeadlessJsTaskConfig(HeadlessJsTaskConfig source) { + mTaskKey = source.mTaskKey; + mData = source.mData.copy(); + mTimeout = source.mTimeout; + mAllowedInForeground = source.mAllowedInForeground; + + final HeadlessJsTaskRetryPolicy retryPolicy = source.mRetryPolicy; + if (retryPolicy != null) { + mRetryPolicy = retryPolicy.copy(); + } else { + mRetryPolicy = null; + } } /* package */ String getTaskKey() { @@ -76,4 +118,8 @@ public HeadlessJsTaskConfig( /* package */ boolean isAllowedInForeground() { return mAllowedInForeground; } + + /* package */ HeadlessJsTaskRetryPolicy getRetryPolicy() { + return mRetryPolicy; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java index fbf38f1a41ee4a..e69505f396a9cd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java @@ -5,12 +5,6 @@ package com.facebook.react.jstasks; -import java.lang.ref.WeakReference; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicInteger; - import android.os.Handler; import android.util.SparseArray; @@ -20,6 +14,14 @@ import com.facebook.react.common.LifecycleState; import com.facebook.react.modules.appregistry.AppRegistry; +import java.lang.ref.WeakReference; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicInteger; + /** * Helper class for dealing with JS tasks. Handles per-ReactContext active task tracking, starting / * stopping tasks and notifying listeners. @@ -51,6 +53,7 @@ public static HeadlessJsTaskContext getInstance(ReactContext context) { private final AtomicInteger mLastTaskId = new AtomicInteger(0); private final Handler mHandler = new Handler(); private final Set mActiveTasks = new CopyOnWriteArraySet<>(); + private final Map mActiveTaskConfigs = new ConcurrentHashMap<>(); private final SparseArray mTaskTimeouts = new SparseArray<>(); private HeadlessJsTaskContext(ReactContext reactContext) { @@ -85,6 +88,16 @@ public boolean hasActiveTasks() { * @return a unique id representing this task instance. */ public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) { + final int taskId = mLastTaskId.incrementAndGet(); + startTask(taskConfig, taskId); + return taskId; + } + + /** + * Start a JS task the provided task id. Handles invoking {@link AppRegistry#startHeadlessTask} + * and notifying listeners. + */ + private synchronized void startTask(final HeadlessJsTaskConfig taskConfig, int taskId) { UiThreadUtil.assertOnUiThread(); ReactContext reactContext = Assertions.assertNotNull( mReactContext.get(), @@ -95,8 +108,8 @@ public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) { "Tried to start task " + taskConfig.getTaskKey() + " while in foreground, but this is not allowed."); } - final int taskId = mLastTaskId.incrementAndGet(); mActiveTasks.add(taskId); + mActiveTaskConfigs.put(taskId, new HeadlessJsTaskConfig(taskConfig)); reactContext.getJSModule(AppRegistry.class) .startHeadlessTask(taskId, taskConfig.getTaskKey(), taskConfig.getData()); if (taskConfig.getTimeout() > 0) { @@ -105,7 +118,44 @@ public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) { for (HeadlessJsTaskEventListener listener : mHeadlessJsTaskEventListeners) { listener.onHeadlessJsTaskStart(taskId); } - return taskId; + } + + /** + * Retry a running JS task with a delay. Invokes + * {@link HeadlessJsTaskContext#startTask(HeadlessJsTaskConfig, int)} as long as the process does + * not get killed. + * + * @return true if a retry attempt has been posted. + */ + public synchronized boolean retryTask(final int taskId) { + final HeadlessJsTaskConfig sourceTaskConfig = mActiveTaskConfigs.get(taskId); + Assertions.assertCondition( + sourceTaskConfig != null, + "Tried to retrieve non-existent task config with id " + taskId + "."); + + final HeadlessJsTaskRetryPolicy retryPolicy = sourceTaskConfig.getRetryPolicy(); + if (!retryPolicy.canRetry()) { + return false; + } + + removeTimeout(taskId); + final HeadlessJsTaskConfig taskConfig = new HeadlessJsTaskConfig( + sourceTaskConfig.getTaskKey(), + sourceTaskConfig.getData(), + sourceTaskConfig.getTimeout(), + sourceTaskConfig.isAllowedInForeground(), + retryPolicy.update() + ); + + final Runnable retryAttempt = new Runnable() { + @Override + public void run() { + startTask(taskConfig, taskId); + } + }; + + UiThreadUtil.runOnUiThread(retryAttempt, retryPolicy.getDelay()); + return true; } /** @@ -118,11 +168,10 @@ public synchronized void finishTask(final int taskId) { Assertions.assertCondition( mActiveTasks.remove(taskId), "Tried to finish non-existent task with id " + taskId + "."); - Runnable timeout = mTaskTimeouts.get(taskId); - if (timeout != null) { - mHandler.removeCallbacks(timeout); - mTaskTimeouts.remove(taskId); - } + Assertions.assertCondition( + mActiveTaskConfigs.remove(taskId) != null, + "Tried to remove non-existent task config with id " + taskId + "."); + removeTimeout(taskId); UiThreadUtil.runOnUiThread(new Runnable() { @Override public void run() { @@ -133,6 +182,14 @@ public void run() { }); } + private void removeTimeout(int taskId) { + Runnable timeout = mTaskTimeouts.get(taskId); + if (timeout != null) { + mHandler.removeCallbacks(timeout); + mTaskTimeouts.remove(taskId); + } + } + /** * Check if a given task is currently running. A task is stopped if either {@link #finishTask} is * called or it times out. diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java new file mode 100644 index 00000000000000..215f5b8b44cb8a --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java @@ -0,0 +1,16 @@ +package com.facebook.react.jstasks; + +import javax.annotation.CheckReturnValue; + +public interface HeadlessJsTaskRetryPolicy { + + boolean canRetry(); + + int getDelay(); + + @CheckReturnValue + HeadlessJsTaskRetryPolicy update(); + + HeadlessJsTaskRetryPolicy copy(); + +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java new file mode 100644 index 00000000000000..b319d35435ead1 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java @@ -0,0 +1,38 @@ +package com.facebook.react.jstasks; + +public class LinearCountingRetryPolicy implements HeadlessJsTaskRetryPolicy { + + private final int mRetryAttempts; + private final int mDelayBetweenAttemptsInMs; + + public LinearCountingRetryPolicy(int retryAttempts, int delayBetweenAttemptsInMs) { + mRetryAttempts = retryAttempts; + mDelayBetweenAttemptsInMs = delayBetweenAttemptsInMs; + } + + @Override + public boolean canRetry() { + return mRetryAttempts > 0; + } + + @Override + public int getDelay() { + return mDelayBetweenAttemptsInMs; + } + + @Override + public HeadlessJsTaskRetryPolicy update() { + final int remainingRetryAttempts = mRetryAttempts - 1; + + if (remainingRetryAttempts > 0) { + return new LinearCountingRetryPolicy(remainingRetryAttempts, mDelayBetweenAttemptsInMs); + } else { + return NoRetryPolicy.INSTANCE; + } + } + + @Override + public HeadlessJsTaskRetryPolicy copy() { + return new LinearCountingRetryPolicy(mRetryAttempts, mDelayBetweenAttemptsInMs); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java new file mode 100644 index 00000000000000..ac707ab70d7789 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java @@ -0,0 +1,30 @@ +package com.facebook.react.jstasks; + +public class NoRetryPolicy implements HeadlessJsTaskRetryPolicy { + + public static final NoRetryPolicy INSTANCE = new NoRetryPolicy(); + + private NoRetryPolicy() { + } + + @Override + public boolean canRetry() { + return false; + } + + @Override + public int getDelay() { + throw new IllegalStateException("Should not retrieve delay as canRetry is: " + canRetry()); + } + + @Override + public HeadlessJsTaskRetryPolicy update() { + throw new IllegalStateException("Should not update as canRetry is: " + canRetry()); + } + + @Override + public HeadlessJsTaskRetryPolicy copy() { + // Class is immutable so no need to copy + return this; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java index 2d783585a77a6d..e9c2cae2a69c9a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java @@ -8,6 +8,7 @@ package com.facebook.react.modules.core; import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; @@ -32,6 +33,22 @@ public String getName() { return NAME; } + @ReactMethod + public void notifyTaskRetry(int taskId, Promise promise) { + HeadlessJsTaskContext headlessJsTaskContext = + HeadlessJsTaskContext.getInstance(getReactApplicationContext()); + if (headlessJsTaskContext.isTaskRunning(taskId)) { + final boolean retryPosted = headlessJsTaskContext.retryTask(taskId); + promise.resolve(retryPosted); + } else { + FLog.w( + HeadlessJsTaskSupportModule.class, + "Tried to retry non-active task with id %d. Did it time out?", + taskId); + promise.resolve(false); + } + } + @ReactMethod public void notifyTaskFinished(int taskId) { HeadlessJsTaskContext headlessJsTaskContext = From 14f249178ef46db9dc1e1200c9ce5a27fc25524a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rain=20=E2=81=A3?= Date: Thu, 6 Jun 2019 19:36:56 -0700 Subject: [PATCH 125/330] standardize C-like MIT copyright headers throughout fbsource Summary: `/*` is the standard throughout open source code. For example, Firefox uses single /*: https://hg.mozilla.org/mozilla-central/file/21d22b2f541258d3d1cf96c7ba5ad73e96e616b5/gfx/ipc/CompositorWidgetVsyncObserver.cpp#l3 In addition, Rust considers `/**` to be a doc comment (similar to Javadoc) and having such a comment at the beginning of the file causes `rustc` to barf. Note that some JavaScript tooling requires `/**`. This is OK since JavaScript files were not covered by the linter in the first place, but it would be good to have that tooling fixed too. Reviewed By: zertosh Differential Revision: D15640366 fbshipit-source-id: b4ed4599071516364d6109720750d6a43304c089 --- ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp | 2 +- ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp | 2 +- ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h | 2 +- ReactCommon/jsi/jsi/JSIDynamic.cpp | 2 +- ReactCommon/jsi/jsi/JSIDynamic.h | 2 +- ReactCommon/jsi/jsi/decorator.h | 2 +- ReactCommon/jsi/jsi/instrumentation.h | 2 +- ReactCommon/jsi/jsi/jsi-inl.h | 2 +- ReactCommon/jsi/jsi/jsi.cpp | 2 +- ReactCommon/jsi/jsi/jsi.h | 2 +- ReactCommon/jsi/jsi/jsilib-posix.cpp | 2 +- ReactCommon/jsi/jsi/jsilib-windows.cpp | 2 +- ReactCommon/jsi/jsi/jsilib.h | 2 +- ReactCommon/jsi/jsi/test/testlib.cpp | 2 +- ReactCommon/jsi/jsi/test/testlib.h | 2 +- ReactCommon/jsi/jsi/threadsafe.h | 2 +- ReactCommon/yoga/yoga/CompactValue.h | 2 +- ReactCommon/yoga/yoga/Utils.cpp | 2 +- ReactCommon/yoga/yoga/Utils.h | 2 +- ReactCommon/yoga/yoga/YGConfig.cpp | 2 +- ReactCommon/yoga/yoga/YGConfig.h | 2 +- ReactCommon/yoga/yoga/YGEnums.cpp | 2 +- ReactCommon/yoga/yoga/YGEnums.h | 2 +- ReactCommon/yoga/yoga/YGFloatOptional.h | 2 +- ReactCommon/yoga/yoga/YGLayout.cpp | 2 +- ReactCommon/yoga/yoga/YGLayout.h | 2 +- ReactCommon/yoga/yoga/YGMacros.h | 2 +- ReactCommon/yoga/yoga/YGMarker.cpp | 2 +- ReactCommon/yoga/yoga/YGMarker.h | 2 +- ReactCommon/yoga/yoga/YGNode.cpp | 2 +- ReactCommon/yoga/yoga/YGNode.h | 2 +- ReactCommon/yoga/yoga/YGNodePrint.cpp | 2 +- ReactCommon/yoga/yoga/YGNodePrint.h | 2 +- ReactCommon/yoga/yoga/YGStyle.cpp | 2 +- ReactCommon/yoga/yoga/YGStyle.h | 2 +- ReactCommon/yoga/yoga/YGValue.cpp | 2 +- ReactCommon/yoga/yoga/YGValue.h | 2 +- ReactCommon/yoga/yoga/Yoga-internal.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/Yoga.h | 2 +- ReactCommon/yoga/yoga/event/event.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 2 +- ReactCommon/yoga/yoga/instrumentation.h | 2 +- ReactCommon/yoga/yoga/log.cpp | 2 +- ReactCommon/yoga/yoga/log.h | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 28011661441036..5a2ce90cc6bdaa 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp index 6be244958b827d..032be5c5e499aa 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index c2c5fc518e3070..21bf395977592b 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/JSIDynamic.cpp b/ReactCommon/jsi/jsi/JSIDynamic.cpp index f63254e94fbe8a..2640c81c3faf87 100644 --- a/ReactCommon/jsi/jsi/JSIDynamic.cpp +++ b/ReactCommon/jsi/jsi/JSIDynamic.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/JSIDynamic.h b/ReactCommon/jsi/jsi/JSIDynamic.h index be28b532eb7e7d..2ad0f55c7601b9 100644 --- a/ReactCommon/jsi/jsi/JSIDynamic.h +++ b/ReactCommon/jsi/jsi/JSIDynamic.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/decorator.h b/ReactCommon/jsi/jsi/decorator.h index ac30bbe58544a1..c073569287bfd2 100644 --- a/ReactCommon/jsi/jsi/decorator.h +++ b/ReactCommon/jsi/jsi/decorator.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/instrumentation.h b/ReactCommon/jsi/jsi/instrumentation.h index f10fb69fbe88fb..595e6889c1c081 100644 --- a/ReactCommon/jsi/jsi/instrumentation.h +++ b/ReactCommon/jsi/jsi/instrumentation.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsi-inl.h b/ReactCommon/jsi/jsi/jsi-inl.h index c15d22f6e44965..5e53f7191b7db3 100644 --- a/ReactCommon/jsi/jsi/jsi-inl.h +++ b/ReactCommon/jsi/jsi/jsi-inl.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsi.cpp b/ReactCommon/jsi/jsi/jsi.cpp index 719dd9310b499e..90ec784ef2eeca 100644 --- a/ReactCommon/jsi/jsi/jsi.cpp +++ b/ReactCommon/jsi/jsi/jsi.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsi.h b/ReactCommon/jsi/jsi/jsi.h index 14334d2c4fc258..c05c5ae369bffc 100644 --- a/ReactCommon/jsi/jsi/jsi.h +++ b/ReactCommon/jsi/jsi/jsi.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsilib-posix.cpp b/ReactCommon/jsi/jsi/jsilib-posix.cpp index e020437ab7175c..91c9e3820da811 100644 --- a/ReactCommon/jsi/jsi/jsilib-posix.cpp +++ b/ReactCommon/jsi/jsi/jsilib-posix.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsilib-windows.cpp b/ReactCommon/jsi/jsi/jsilib-windows.cpp index 69581bbbeab567..d01c0e341b757a 100644 --- a/ReactCommon/jsi/jsi/jsilib-windows.cpp +++ b/ReactCommon/jsi/jsi/jsilib-windows.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsilib.h b/ReactCommon/jsi/jsi/jsilib.h index 49967f4aa449f4..5a359619bd7d78 100644 --- a/ReactCommon/jsi/jsi/jsilib.h +++ b/ReactCommon/jsi/jsi/jsilib.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/test/testlib.cpp b/ReactCommon/jsi/jsi/test/testlib.cpp index 640fb133570395..71e2bf4389aa91 100644 --- a/ReactCommon/jsi/jsi/test/testlib.cpp +++ b/ReactCommon/jsi/jsi/test/testlib.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/test/testlib.h b/ReactCommon/jsi/jsi/test/testlib.h index 604fc044d6f773..ef8adda4a45403 100644 --- a/ReactCommon/jsi/jsi/test/testlib.h +++ b/ReactCommon/jsi/jsi/test/testlib.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/threadsafe.h b/ReactCommon/jsi/jsi/threadsafe.h index 2e1fb918b11341..aeef85fa3b95e3 100644 --- a/ReactCommon/jsi/jsi/threadsafe.h +++ b/ReactCommon/jsi/jsi/threadsafe.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/CompactValue.h b/ReactCommon/yoga/yoga/CompactValue.h index 2045177951a81d..899dcc58c26048 100644 --- a/ReactCommon/yoga/yoga/CompactValue.h +++ b/ReactCommon/yoga/yoga/CompactValue.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index 38b686c581a7bd..8864155bd7cc34 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 900ccb1bee6736..d6fbc26891ffca 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGConfig.cpp b/ReactCommon/yoga/yoga/YGConfig.cpp index 773ad24aba7e96..4e805823d03da3 100644 --- a/ReactCommon/yoga/yoga/YGConfig.cpp +++ b/ReactCommon/yoga/yoga/YGConfig.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGConfig.h b/ReactCommon/yoga/yoga/YGConfig.h index 311c159701b6ff..aaf6d1370efcd4 100644 --- a/ReactCommon/yoga/yoga/YGConfig.h +++ b/ReactCommon/yoga/yoga/YGConfig.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGEnums.cpp b/ReactCommon/yoga/yoga/YGEnums.cpp index ff4b130766f00c..bf5844c57cf092 100644 --- a/ReactCommon/yoga/yoga/YGEnums.cpp +++ b/ReactCommon/yoga/yoga/YGEnums.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGEnums.h b/ReactCommon/yoga/yoga/YGEnums.h index f06b0e045cf9a4..b3c57fb835992f 100644 --- a/ReactCommon/yoga/yoga/YGEnums.h +++ b/ReactCommon/yoga/yoga/YGEnums.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h index 7ca1fc12134cba..60fcad99be0049 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGLayout.cpp b/ReactCommon/yoga/yoga/YGLayout.cpp index 6f55d862ca69be..d1144ea6f26dac 100644 --- a/ReactCommon/yoga/yoga/YGLayout.cpp +++ b/ReactCommon/yoga/yoga/YGLayout.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGLayout.h b/ReactCommon/yoga/yoga/YGLayout.h index 0e559d7429b322..1b30cc8ce29221 100644 --- a/ReactCommon/yoga/yoga/YGLayout.h +++ b/ReactCommon/yoga/yoga/YGLayout.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGMacros.h b/ReactCommon/yoga/yoga/YGMacros.h index badea8c3c3e489..d56f3aeb7377f0 100644 --- a/ReactCommon/yoga/yoga/YGMacros.h +++ b/ReactCommon/yoga/yoga/YGMacros.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGMarker.cpp b/ReactCommon/yoga/yoga/YGMarker.cpp index 21a8d1f6cad4a3..e0758e2308bfa5 100644 --- a/ReactCommon/yoga/yoga/YGMarker.cpp +++ b/ReactCommon/yoga/yoga/YGMarker.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGMarker.h b/ReactCommon/yoga/yoga/YGMarker.h index 89b03684312b6a..625adc2cece8fa 100644 --- a/ReactCommon/yoga/yoga/YGMarker.h +++ b/ReactCommon/yoga/yoga/YGMarker.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 81a4216eb6616a..8941487fb5e097 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 1ef8014214b8e0..cc11cc88d836bd 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp index 301e72a2e28acb..f91d037462ebde 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNodePrint.h b/ReactCommon/yoga/yoga/YGNodePrint.h index 13cf367b531adb..8df30e2ccc6427 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.h +++ b/ReactCommon/yoga/yoga/YGNodePrint.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index 6672c81faafcf6..a4a7a0473ac1b8 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGStyle.h b/ReactCommon/yoga/yoga/YGStyle.h index 77c7e0386874e7..edefcb7cc9db54 100644 --- a/ReactCommon/yoga/yoga/YGStyle.h +++ b/ReactCommon/yoga/yoga/YGStyle.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGValue.cpp b/ReactCommon/yoga/yoga/YGValue.cpp index fcdd0c6931b007..995f211391afda 100644 --- a/ReactCommon/yoga/yoga/YGValue.cpp +++ b/ReactCommon/yoga/yoga/YGValue.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGValue.h b/ReactCommon/yoga/yoga/YGValue.h index 170047ea596197..0405bc6288bd4e 100644 --- a/ReactCommon/yoga/yoga/YGValue.h +++ b/ReactCommon/yoga/yoga/YGValue.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Yoga-internal.h b/ReactCommon/yoga/yoga/Yoga-internal.h index 4d32a96bcec13d..34c0b077f793e6 100644 --- a/ReactCommon/yoga/yoga/Yoga-internal.h +++ b/ReactCommon/yoga/yoga/Yoga-internal.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index d41a12013cd75d..bf02dd9965cd07 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index a9dc01dcab1f67..6ec796d84b23a8 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/event/event.cpp b/ReactCommon/yoga/yoga/event/event.cpp index 02e70dce02eb33..9fc00120935e9b 100644 --- a/ReactCommon/yoga/yoga/event/event.cpp +++ b/ReactCommon/yoga/yoga/event/event.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 578d2f3a66a5e8..1937dafcc10c94 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/instrumentation.h b/ReactCommon/yoga/yoga/instrumentation.h index b8691c1865b014..e15f2fb1e45d79 100644 --- a/ReactCommon/yoga/yoga/instrumentation.h +++ b/ReactCommon/yoga/yoga/instrumentation.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/log.cpp b/ReactCommon/yoga/yoga/log.cpp index 62b3d4f0589769..45e5f7b16a3e42 100644 --- a/ReactCommon/yoga/yoga/log.cpp +++ b/ReactCommon/yoga/yoga/log.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/log.h b/ReactCommon/yoga/yoga/log.h index f25ee1a2b0c397..effe23b5b96a00 100644 --- a/ReactCommon/yoga/yoga/log.h +++ b/ReactCommon/yoga/yoga/log.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE From c44b221e134d32a5b60dde0fd5c817773fbfbbdd Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Thu, 6 Jun 2019 20:59:24 -0700 Subject: [PATCH 126/330] moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event Summary: Move PtrJNodeMap to header file so that it can be accessed in events subscribers outside yoga Reviewed By: davidaurelio Differential Revision: D15619629 fbshipit-source-id: 1bf213efd38ec7bcac6a38070f21fa837c5f17da --- .../jni/first-party/yogajni/jni/YGJNI.cpp | 28 ---------------- .../jni/first-party/yogajni/jni/YGJTypes.h | 33 +++++++++++++++++++ ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 5 +++ 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 5a2ce90cc6bdaa..f12836816788ac 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -75,34 +75,6 @@ const short int LAYOUT_BORDER_START_INDEX = 14; bool useBatchingForLayoutOutputs; -class PtrJNodeMap { - using JNodeArray = JArrayClass; - std::map ptrsToIdxs_; - alias_ref javaNodes_; - -public: - PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} - PtrJNodeMap( - alias_ref nativePointers, - alias_ref javaNodes) - : javaNodes_{javaNodes} { - auto pin = nativePointers->pinCritical(); - auto ptrs = pin.get(); - for (size_t i = 0, n = pin.size(); i < n; ++i) { - ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; - } - } - - local_ref ref(YGNodeRef node) { - auto idx = ptrsToIdxs_.find(node); - if (idx == ptrsToIdxs_.end()) { - return local_ref{}; - } else { - return javaNodes_->getElement(idx->second); - } - } -}; - namespace { union YGNodeContext { diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index 21bf395977592b..bd8e6c7b947e53 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -6,6 +6,11 @@ */ #include #include +#include +#include + +using namespace facebook::jni; +using namespace std; struct JYogaNode : public facebook::jni::JavaClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNodeJNIBase;"; @@ -28,3 +33,31 @@ struct JYogaLogger : public facebook::jni::JavaClass { facebook::jni::alias_ref, jstring); }; + +class PtrJNodeMap { + using JNodeArray = JArrayClass; + std::map ptrsToIdxs_; + alias_ref javaNodes_; + +public: + PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} + PtrJNodeMap( + alias_ref nativePointers, + alias_ref javaNodes) + : javaNodes_{javaNodes} { + auto pin = nativePointers->pinCritical(); + auto ptrs = pin.get(); + for (size_t i = 0, n = pin.size(); i < n; ++i) { + ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; + } + } + + local_ref ref(YGNodeRef node) { + auto idx = ptrsToIdxs_.find(node); + if (idx == ptrsToIdxs_.end()) { + return local_ref{}; + } else { + return javaNodes_->getElement(idx->second); + } + } +}; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index bf02dd9965cd07..763d9bfcdca890 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -4093,7 +4093,7 @@ void YGNodeCalculateLayoutWithContext( marker = nullptr; #ifdef YG_ENABLE_EVENTS - Event::publish(node); + Event::publish(node, {layoutContext}); #endif // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 1937dafcc10c94..f0f427974a5c9c 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -71,5 +71,10 @@ struct Event::TypedData { YGConfig* config; }; +template <> +struct Event::TypedData { + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From 348c3ebefafb881ec839209e01118f8cbcfa162e Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Thu, 6 Jun 2019 20:59:24 -0700 Subject: [PATCH 127/330] add node measure event and passing the callback to java layer Summary: Adds measure event and its listener initial code structure Reviewed By: davidaurelio Differential Revision: D15600738 fbshipit-source-id: d15764e0b64edb170fcb15e0912ecce5f7e53595 --- .../main/java/com/facebook/yoga/YogaEventListener.java | 4 +++- ReactCommon/yoga/yoga/Yoga.cpp | 4 ++++ ReactCommon/yoga/yoga/event/event.h | 8 +++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java index 6d1d486be28a44..97791224577d67 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java @@ -10,4 +10,6 @@ public interface YogaEventListener { void onLayoutPassEnd(YogaNode node); -} \ No newline at end of file + void onNodeMeasure(YogaNode node); + +} diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 763d9bfcdca890..c46104be1d33e1 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1635,6 +1635,10 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( heightMeasureMode, layoutContext); +#ifdef YG_ENABLE_EVENTS + Event::publish(node, {layoutContext}); +#endif + node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index f0f427974a5c9c..bff8dbfd8952fc 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -21,7 +21,8 @@ struct Event { NodeDeallocation, NodeLayout, LayoutPassStart, - LayoutPassEnd + LayoutPassEnd, + NodeMeasure, }; class Data; using Subscriber = void(const YGNode&, Type, Data); @@ -76,5 +77,10 @@ struct Event::TypedData { void* layoutContext; }; +template <> +struct Event::TypedData { + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From d9a8ac5071d23275c5d4a8e9936f391b967416d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=91=D1=82=D1=80=20=D0=9F=D0=BE=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 7 Jun 2019 02:44:21 -0700 Subject: [PATCH 128/330] Fix: RefreshControl in FlatList makes borderWidth not working (#24411) Summary: Fixes #22752 On line 1021 you are passing base style to props: `style: [baseStyle, this.props.style],` Explicitly passing base style to ScrollView just overrides this line and doesn't let developers to customise style of any inheritors of ScrollView (not only FlatList) with custom RefreshControl. So this line (1113) seems to be removed. ## Changelog [GENERAL] [Fixed] - fix of Android's bug that doesn't let override ScrollView's Style with custom RefreshControl. Pull Request resolved: https://github.com/facebook/react-native/pull/24411 Differential Revision: D15713061 Pulled By: cpojer fbshipit-source-id: 461259800f867af15e53e0743a5057ea4528ae69 --- Libraries/Components/ScrollView/ScrollView.js | 9 +-- .../__tests__/splitLayoutProps-test.js | 44 +++++++++++++ Libraries/StyleSheet/splitLayoutProps.js | 62 +++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 Libraries/StyleSheet/__tests__/splitLayoutProps-test.js create mode 100644 Libraries/StyleSheet/splitLayoutProps.js diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index f28d77908811fe..260bc0fd94c10d 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -25,6 +25,7 @@ const invariant = require('invariant'); const processDecelerationRate = require('./processDecelerationRate'); const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); const resolveAssetSource = require('../../Image/resolveAssetSource'); +const splitLayoutProps = require('../../StyleSheet/splitLayoutProps'); import type { PressEvent, @@ -1125,15 +1126,15 @@ class ScrollView extends React.Component { // On Android wrap the ScrollView with a AndroidSwipeRefreshLayout. // Since the ScrollView is wrapped add the style props to the // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView. - // Note: we should only apply props.style on the wrapper + // Note: we should split props.style on the inner and outer props // however, the ScrollView still needs the baseStyle to be scrollable - + const {outer, inner} = splitLayoutProps(flattenStyle(props.style)); return React.cloneElement( refreshControl, - {style: props.style}, + {style: [baseStyle, outer]}, {contentContainer} diff --git a/Libraries/StyleSheet/__tests__/splitLayoutProps-test.js b/Libraries/StyleSheet/__tests__/splitLayoutProps-test.js new file mode 100644 index 00000000000000..70b2877ae2cc4d --- /dev/null +++ b/Libraries/StyleSheet/__tests__/splitLayoutProps-test.js @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @emails oncall+react_native + */ + +'use strict'; + +const splitLayoutProps = require('../splitLayoutProps'); + +test('splits style objects', () => { + const style = {width: 10, margin: 20, padding: 30}; + const {outer, inner} = splitLayoutProps(style); + expect(outer).toMatchInlineSnapshot(` + Object { + "margin": 20, + "width": 10, + } + `); + expect(inner).toMatchInlineSnapshot(` + Object { + "padding": 30, + } + `); +}); + +test('does not copy values to both returned objects', () => { + const style = {marginVertical: 5, paddingHorizontal: 10}; + const {outer, inner} = splitLayoutProps(style); + expect(outer).toMatchInlineSnapshot(` + Object { + "marginVertical": 5, + } + `); + expect(inner).toMatchInlineSnapshot(` + Object { + "paddingHorizontal": 10, + } + `); +}); diff --git a/Libraries/StyleSheet/splitLayoutProps.js b/Libraries/StyleSheet/splitLayoutProps.js new file mode 100644 index 00000000000000..700fbea437f893 --- /dev/null +++ b/Libraries/StyleSheet/splitLayoutProps.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +import type {DangerouslyImpreciseStyle} from './StyleSheet'; + +const OUTER_PROPS = Object.assign(Object.create(null), { + margin: true, + marginHorizontal: true, + marginVertical: true, + marginBottom: true, + marginTop: true, + marginLeft: true, + marginRight: true, + flex: true, + flexGrow: true, + flexShrink: true, + flexBasis: true, + alignSelf: true, + height: true, + minHeight: true, + maxHeight: true, + width: true, + minWidth: true, + maxWidth: true, + position: true, + left: true, + right: true, + bottom: true, + top: true, +}); + +function splitLayoutProps( + props: ?DangerouslyImpreciseStyle, +): { + outer: DangerouslyImpreciseStyle, + inner: DangerouslyImpreciseStyle, +} { + const inner = {}; + const outer = {}; + if (props) { + Object.keys(props).forEach(k => { + const value: $ElementType = props[k]; + if (OUTER_PROPS[k]) { + outer[k] = value; + } else { + inner[k] = value; + } + }); + } + return {outer, inner}; +} + +module.exports = splitLayoutProps; From 3b1dbccaaf90aa05a0b25e4853e6b8d48da1deaf Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 7 Jun 2019 02:55:28 -0700 Subject: [PATCH 129/330] Do a hard reload if hot update can't be applied MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Hot reloading propagates upwards through the inverse dependency tree — from a file you edited, to the files that import it, and so on. However, we can't always reevaluate everything. Many core infra modules can't run twice, and also the more you run, the more the risk of encountering a module with init side effects. So our practical compromise is to stop the propagation when we reach a module whose exports look like React components. We say that such module "accepts" an update. This means that in practice, changes trigger module reevaluation up to the closest component modules from the edited file. (If you edited a component file, it re-executes alone — unless it exports a non-component.) However, current implementation has a problem. Sometimes there is an inverse dependency path that has no "accepting" modules whatsoever. For example, maybe you're editing some core module, and its inverse dependency tree reaches goes into React Native itself. Or maybe it reaches the entry point with a bunch of side effects that can't be repeated, like registering the app root component. In the past, such cases would lead to confusing errors like "Expected `FBPrelude.conclude()` to have been called" after hot reload. This was because we kept re-executing modules all the way upwards, even if there is nothing that can accept the update on the path. Eventually we'd reach top-level modules in the import graph that don't like to run twice. This diff changes the logic so that we *don't attempt* to re-execute the module factories if we know that some inverse dependency path doesn't terminate in a component. In that case we know we simply *can't apply the hot update* because it doesn't stop at a point we can handle, like a React component. Since the hot update fails in this case, I'm making it fall back to a regular reload. This is similar to how webpack handles a similar situation on the web. This means that hot updates normally don't refresh, but if we can't apply a hot update to this file, we do refresh automatically. Reviewed By: cpojer Differential Revision: D15631864 fbshipit-source-id: 52cd1b03739fd760f1b1b1ab8c7276a150cc3c4c --- Libraries/Core/InitializeCore.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 263001547b6132..a3e19687e4bb46 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -42,6 +42,15 @@ require('./setUpSegmentFetcher'); if (__DEV__) { require('./checkNativeVersion'); require('./setUpDeveloperTools'); + + // This is used by the require.js polyfill for hot reloading. + // TODO(t9759686) Scan polyfills for dependencies, too + const reload = require('../NativeModules/specs/NativeDevSettings').default + .reload; + if (typeof reload !== 'function') { + throw new Error('Could not find the reload() implementation.'); + } + (require: any).reload = reload; } const GlobalPerformanceLogger = require('../Utilities/GlobalPerformanceLogger'); From ea090a10e63bb75ab9446ed2bd84647bf3d28bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 7 Jun 2019 03:04:54 -0700 Subject: [PATCH 130/330] Bump CLI to 2.0.0-rc.0 (#25175) Summary: Upgrading the CLI to the latest with a bunch of fixes and features included. ## Changelog [General] [Changed] - Bump CLI to 2.0.0-rc.0 Pull Request resolved: https://github.com/facebook/react-native/pull/25175 Differential Revision: D15694764 Pulled By: cpojer fbshipit-source-id: 25fbf1c275ed5379e1cdb372512b6bb6327dea92 --- jest/hasteImpl.js | 16 ---------------- package.json | 6 +++--- yarn.lock | 42 +++++++++++++++++++++--------------------- 3 files changed, 24 insertions(+), 40 deletions(-) delete mode 100644 jest/hasteImpl.js diff --git a/jest/hasteImpl.js b/jest/hasteImpl.js deleted file mode 100644 index d1c1fad686ba5d..00000000000000 --- a/jest/hasteImpl.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -module.exports = { - getHasteName() { - return undefined; - }, -}; diff --git a/package.json b/package.json index 0be5ffb403a123..0a3190a401376a 100644 --- a/package.json +++ b/package.json @@ -82,9 +82,9 @@ }, "dependencies": { "@babel/runtime": "^7.0.0", - "@react-native-community/cli": "2.0.0-alpha.23", - "@react-native-community/cli-platform-android": "2.0.0-alpha.23", - "@react-native-community/cli-platform-ios": "2.0.0-alpha.23", + "@react-native-community/cli": "2.0.0-rc.0", + "@react-native-community/cli-platform-android": "2.0.0-rc.0", + "@react-native-community/cli-platform-ios": "2.0.0-rc.0", "abort-controller": "^3.0.0", "art": "^0.10.0", "base64-js": "^1.1.2", diff --git a/yarn.lock b/yarn.lock index 9c5859f6db42db..b39d6f59e1a8d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1090,44 +1090,44 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" -"@react-native-community/cli-platform-android@2.0.0-alpha.23", "@react-native-community/cli-platform-android@^2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-alpha.23.tgz#f4941cca17eedef694bf420027b816ecd2e1f1c3" - integrity sha512-V57NWTyi20VQA2EPL1xmiibIQD0bUVe0ecVQxSb903f4M3ml0x4TEqWOToE2wgda/c4Z3pEKJuRCzyZHfuEYPA== +"@react-native-community/cli-platform-android@2.0.0-rc.0", "@react-native-community/cli-platform-android@^2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-rc.0.tgz#8fcc57a68b3f971d322034c21ba09c580ce5455a" + integrity sha512-i9xCMx1AFTscFlEsUJZVn5r6h7ndjvBUUTgLR/4oV639Bcwlci3OvKD1bV5fdp1/L9Mv14iuDo7y1Jv9ubRi5w== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.23" + "@react-native-community/cli-tools" "^2.0.0-rc.0" logkitty "^0.4.0" slash "^2.0.0" xmldoc "^0.4.0" -"@react-native-community/cli-platform-ios@2.0.0-alpha.23", "@react-native-community/cli-platform-ios@^2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-alpha.23.tgz#3ef22cc5d5ce32b85f9f9604056ca3cea652a59a" - integrity sha512-jAffpJNw9zrlI5rwM/BfaTNtKjrx+Rvuei1YqfjLaQKUiXgrbJYbIu9+6Lc+sAn1qFGwL2+CShpywwbvN2ehGQ== +"@react-native-community/cli-platform-ios@2.0.0-rc.0", "@react-native-community/cli-platform-ios@^2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-rc.0.tgz#00489529d1715c80042a1649b0c6822aa7c785ba" + integrity sha512-v1BxVFHrrypI9XVtwtq0FPtZHusvCouPbpX7c4h4SiP66KT/+eAYVuOTpjSN+EMss/WZLeJKIPOiBn2ZohxcwA== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.23" + "@react-native-community/cli-tools" "^2.0.0-rc.0" chalk "^1.1.1" xcode "^2.0.0" -"@react-native-community/cli-tools@^2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-alpha.23.tgz#001a6ef134e1488bf8ef41dd203fda67f7aed8d6" - integrity sha512-+a+IByj0EXQg6M3Q0aT1hsGSmmqWPPkrx+LeY4Gi2pnmOR+DB9A/dDEDOvwxd/OPBsXqzNmdO+iUcg3HNm/twg== +"@react-native-community/cli-tools@^2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-rc.0.tgz#82eedb621921b4511a0a98dbc98eedc12bd98b9b" + integrity sha512-svdIsrcd905lberrY7jVMrHsoCy5PkVgJeiloMFjV6nPTPaKF7ujw2ftdUp9P66KRb7y/IMT5/4EDtntr8SkGg== dependencies: chalk "^1.1.1" lodash "^4.17.5" mime "^2.4.1" node-fetch "^2.5.0" -"@react-native-community/cli@2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-alpha.23.tgz#321ea633ffdf1160170e4428b5886f4d731ff373" - integrity sha512-NIIRgdqA1IA3+K1l1jcXEtS0qL0aos75GXVwGBOmEkC4TfNoOpVQZl2Ffy+/j+IPGpzl2xecOMMmIvlzQRGDtQ== +"@react-native-community/cli@2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-rc.0.tgz#fcc7551e93bc5fad456d26396de3b91b20ae7190" + integrity sha512-juHl7U3DSYjTexWmTiN54YSK52dM2nz0P2sJipZkJLbYSsSJTtvLiRWIKzaG/1Q03EfPp3DbkYTOXQMEERzQEg== dependencies: "@hapi/joi" "^15.0.3" - "@react-native-community/cli-platform-android" "^2.0.0-alpha.23" - "@react-native-community/cli-platform-ios" "^2.0.0-alpha.23" - "@react-native-community/cli-tools" "^2.0.0-alpha.23" + "@react-native-community/cli-platform-android" "^2.0.0-rc.0" + "@react-native-community/cli-platform-ios" "^2.0.0-rc.0" + "@react-native-community/cli-tools" "^2.0.0-rc.0" chalk "^1.1.1" command-exists "^1.2.8" commander "^2.19.0" From 93b9ac74e59bbe84ea388d7c1879857b4acab114 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 7 Jun 2019 06:35:19 -0700 Subject: [PATCH 131/330] Remove Map/Set from RN Open Source Summary: This is the same diff as D14786123 but with one of the buck targets fixed that only failed on continuous and didn't run during land time. This moves Map/Set to fb internal. We do not need them in open source any more but we still need this in some apps at FB that use an old version of JSC. Reviewed By: rickhanlonii Differential Revision: D15713305 fbshipit-source-id: caec43c76a6255b2af1693c13d8dea31d7d674f5 --- Libraries/Core/InitializeCore.js | 1 - .../Core/__tests__/MapAndSetPolyfills-test.js | 102 --- Libraries/Core/polyfillES6Collections.js | 27 - Libraries/vendor/core/Map.js | 590 ------------------ Libraries/vendor/core/Set.js | 198 ------ .../core/_shouldPolyfillES6Collection.js | 66 -- flow/Map.js | 40 -- flow/Set.js | 36 -- 8 files changed, 1060 deletions(-) delete mode 100644 Libraries/Core/__tests__/MapAndSetPolyfills-test.js delete mode 100644 Libraries/Core/polyfillES6Collections.js delete mode 100644 Libraries/vendor/core/Map.js delete mode 100644 Libraries/vendor/core/Set.js delete mode 100644 Libraries/vendor/core/_shouldPolyfillES6Collection.js delete mode 100644 flow/Map.js delete mode 100644 flow/Set.js diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index a3e19687e4bb46..d1807071d03eb3 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -28,7 +28,6 @@ const start = Date.now(); require('./setUpGlobals'); -require('./polyfillES6Collections'); require('./setUpSystrace'); require('./setUpErrorHandling'); require('./polyfillPromise'); diff --git a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js deleted file mode 100644 index 20f54a0e68d9d5..00000000000000 --- a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+react_native - */ -'use strict'; - -// Save these methods so that we can restore them afterward. -const {freeze, seal, preventExtensions} = Object; - -function setup() { - jest.setMock('../../vendor/core/_shouldPolyfillES6Collection', () => true); -} - -function cleanup() { - Object.assign(Object, {freeze, seal, preventExtensions}); -} - -describe('Map polyfill', () => { - setup(); - - const Map = require('../../vendor/core/Map'); - - it('is not native', () => { - const getCode = Function.prototype.toString.call(Map.prototype.get); - expect(getCode).not.toContain('[native code]'); - expect(getCode).toContain('getIndex'); - }); - - it('should tolerate non-extensible object keys', () => { - const map = new Map(); - const key = Object.create(null); - Object.freeze(key); - map.set(key, key); - expect(map.size).toBe(1); - expect(map.has(key)).toBe(true); - map.delete(key); - expect(map.size).toBe(0); - expect(map.has(key)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const map = new Map(); - const proto = Object.create(null); - const base = Object.create(proto); - map.set(proto, proto); - expect(map.size).toBe(1); - expect(map.has(proto)).toBe(true); - expect(map.has(base)).toBe(false); - map.set(base, base); - expect(map.size).toBe(2); - expect(map.get(proto)).toBe(proto); - expect(map.get(base)).toBe(base); - }); - - afterAll(cleanup); -}); - -describe('Set polyfill', () => { - setup(); - - const Set = require('../../vendor/core/Set'); - - it('is not native', () => { - const addCode = Function.prototype.toString.call(Set.prototype.add); - expect(addCode).not.toContain('[native code]'); - }); - - it('should tolerate non-extensible object elements', () => { - const set = new Set(); - const elem = Object.create(null); - Object.freeze(elem); - set.add(elem); - expect(set.size).toBe(1); - expect(set.has(elem)).toBe(true); - set.add(elem); - expect(set.size).toBe(1); - set.delete(elem); - expect(set.size).toBe(0); - expect(set.has(elem)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const set = new Set(); - const proto = Object.create(null); - const base = Object.create(proto); - set.add(proto); - expect(set.size).toBe(1); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(false); - set.add(base); - expect(set.size).toBe(2); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(true); - }); - - afterAll(cleanup); -}); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js deleted file mode 100644 index b58718540fedca..00000000000000 --- a/Libraries/Core/polyfillES6Collections.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ -'use strict'; - -const {polyfillGlobal} = require('../Utilities/PolyfillFunctions'); - -/** - * Polyfill ES6 collections (Map and Set). - * If you don't need these polyfills, don't use InitializeCore; just directly - * require the modules you need from InitializeCore for setup. - */ -const _shouldPolyfillCollection = require('../vendor/core/_shouldPolyfillES6Collection'); -if (_shouldPolyfillCollection('Map')) { - // $FlowFixMe: even in strict-local mode Flow expects Map to be Flow-typed - polyfillGlobal('Map', () => require('../vendor/core/Map')); -} -if (_shouldPolyfillCollection('Set')) { - // $FlowFixMe: even in strict-local mode Flow expects Set to be Flow-typed - polyfillGlobal('Set', () => require('../vendor/core/Set')); -} diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js deleted file mode 100644 index 4f23b1f4783ab8..00000000000000 --- a/Libraries/vendor/core/Map.js +++ /dev/null @@ -1,590 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native, no-shadow-restricted-names */ - -'use strict'; - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const guid = require('./guid'); -const toIterator = require('./toIterator'); - -module.exports = (function(global, undefined) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - if (!_shouldPolyfillES6Collection('Map')) { - return global.Map; - } - - const hasOwn = Object.prototype.hasOwnProperty; - - /** - * == ES6 Map Collection == - * - * This module is meant to implement a Map collection as described in chapter - * 23.1 of the ES6 specification. - * - * Map objects are collections of key/value pairs where both the keys and - * values may be arbitrary ECMAScript language values. A distinct key value - * may only occur in one key/value pair within the Map's collection. - * - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- deviations from the spec: - * - * 1. The use of untagged frozen objects as keys. - * We decided not to allow and simply throw an error, because this - * implementation of Map works by tagging objects used as Map keys - * with a secret hash property for fast access to the object's place - * in the internal _mapData array. However, to limit the impact of - * this spec deviation, Libraries/Core/InitializeCore.js also wraps - * Object.freeze, Object.seal, and Object.preventExtensions so that - * they tag objects before making them non-extensible, by inserting - * each object into a Map and then immediately removing it. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var map = new Map(iterable); - * - * map.set(key, value); - * map.get(key); // value - * map.has(key); // true - * map.delete(key); // true - * - * var iterator = map.keys(); - * iterator.next(); // {value: key, done: false} - * - * var iterator = map.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = map.entries(); - * iterator.next(); // {value: [key, value], done: false} - * - * map.forEach(function(value, key){ this === thisArg }, thisArg); - * - * map.clear(); // resets map. - */ - - /** - * Constants - */ - - // Kinds of map iterations 23.1.5.3 - const KIND_KEY = 'key'; - const KIND_VALUE = 'value'; - const KIND_KEY_VALUE = 'key+value'; - - // In older browsers we can't create a null-prototype object so we have to - // defend against key collisions with built-in methods. - const KEY_PREFIX = '$map_'; - - // This property will be used as the internal size variable to disallow - // writing and to issue warnings for writings in development. - let SECRET_SIZE_PROP; - if (__DEV__) { - SECRET_SIZE_PROP = '$size' + guid(); - } - - class Map { - /** - * 23.1.1.1 - * Takes an `iterable` which is basically any object that implements a - * Symbol.iterator (@@iterator) method. The iterable is expected to be a - * collection of pairs. Each pair is a key/value pair that will be used - * to instantiate the map. - * - * @param {*} iterable - */ - constructor(iterable) { - if (!isObject(this)) { - throw new TypeError('Wrong map object type.'); - } - - initMap(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - if (!isObject(next.value)) { - throw new TypeError('Expected iterable items to be pair objects.'); - } - this.set(next.value[0], next.value[1]); - } - } - } - - /** - * 23.1.3.1 - * Clears the map from all keys and values. - */ - clear() { - initMap(this); - } - - /** - * 23.1.3.7 - * Check if a key exists in the collection. - * - * @param {*} key - * @return {boolean} - */ - has(key) { - const index = getIndex(this, key); - return !!(index != null && this._mapData[index]); - } - - /** - * 23.1.3.9 - * Adds a key/value pair to the collection. - * - * @param {*} key - * @param {*} value - * @return {map} - */ - set(key, value) { - let index = getIndex(this, key); - - if (index != null && this._mapData[index]) { - this._mapData[index][1] = value; - } else { - index = this._mapData.push([key, value]) - 1; - setIndex(this, key, index); - if (__DEV__) { - this[SECRET_SIZE_PROP] += 1; - } else { - this.size += 1; - } - } - - return this; - } - - /** - * 23.1.3.6 - * Gets a value associated with a key in the collection. - * - * @param {*} key - * @return {*} - */ - get(key) { - const index = getIndex(this, key); - if (index == null) { - return undefined; - } else { - return this._mapData[index][1]; - } - } - - /** - * 23.1.3.3 - * Delete a key/value from the collection. - * - * @param {*} key - * @return {boolean} Whether the key was found and deleted. - */ - delete(key) { - const index = getIndex(this, key); - if (index != null && this._mapData[index]) { - setIndex(this, key, undefined); - this._mapData[index] = undefined; - if (__DEV__) { - this[SECRET_SIZE_PROP] -= 1; - } else { - this.size -= 1; - } - return true; - } else { - return false; - } - } - - /** - * 23.1.3.4 - * Returns an iterator over the key/value pairs (in the form of an Array) in - * the collection. - * - * @return {MapIterator} - */ - entries() { - return new MapIterator(this, KIND_KEY_VALUE); - } - - /** - * 23.1.3.8 - * Returns an iterator over the keys in the collection. - * - * @return {MapIterator} - */ - keys() { - return new MapIterator(this, KIND_KEY); - } - - /** - * 23.1.3.11 - * Returns an iterator over the values pairs in the collection. - * - * @return {MapIterator} - */ - values() { - return new MapIterator(this, KIND_VALUE); - } - - /** - * 23.1.3.5 - * Iterates over the key/value pairs in the collection calling `callback` - * with [value, key, map]. An optional `thisArg` can be passed to set the - * context when `callback` is called. - * - * @param {function} callback - * @param {?object} thisArg - */ - forEach(callback, thisArg) { - if (typeof callback !== 'function') { - throw new TypeError('Callback must be callable.'); - } - - const boundCallback = callback.bind(thisArg || undefined); - const mapData = this._mapData; - - // Note that `mapData.length` should be computed on each iteration to - // support iterating over new items in the map that were added after the - // start of the iteration. - for (let i = 0; i < mapData.length; i++) { - const entry = mapData[i]; - if (entry != null) { - boundCallback(entry[1], entry[0], this); - } - } - } - } - - // 23.1.3.12 - Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries; - - class MapIterator { - /** - * 23.1.5.1 - * Create a `MapIterator` for a given `map`. While this class is private it - * will create objects that will be passed around publicily. - * - * @param {map} map - * @param {string} kind - */ - constructor(map, kind) { - if (!(isObject(map) && map._mapData)) { - throw new TypeError('Object is not a map.'); - } - - if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) { - throw new Error('Invalid iteration kind.'); - } - - this._map = map; - this._nextIndex = 0; - this._kind = kind; - } - - /** - * 23.1.5.2.1 - * Get the next iteration. - * - * @return {object} - */ - next() { - if (!this instanceof Map) { - throw new TypeError('Expected to be called on a MapIterator.'); - } - - const map = this._map; - let index = this._nextIndex; - const kind = this._kind; - - if (map == null) { - return createIterResultObject(undefined, true); - } - - const entries = map._mapData; - - while (index < entries.length) { - const record = entries[index]; - - index += 1; - this._nextIndex = index; - - if (record) { - if (kind === KIND_KEY) { - return createIterResultObject(record[0], false); - } else if (kind === KIND_VALUE) { - return createIterResultObject(record[1], false); - } else if (kind) { - return createIterResultObject(record, false); - } - } - } - - this._map = undefined; - - return createIterResultObject(undefined, true); - } - } - - // We can put this in the class definition once we have computed props - // transform. - // 23.1.5.2.2 - MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() { - return this; - }; - - /** - * Helper Functions. - */ - - /** - * Return an index to map.[[MapData]] array for a given Key. - * - * @param {map} map - * @param {*} key - * @return {?number} - */ - function getIndex(map, key) { - if (isObject(key)) { - const hash = getHash(key); - return map._objectIndex[hash]; - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - return map._stringIndex[prefixedKey]; - } else { - return map._otherIndex[prefixedKey]; - } - } - } - - /** - * Setup an index that refer to the key's location in map.[[MapData]]. - * - * @param {map} map - * @param {*} key - */ - function setIndex(map, key, index) { - const shouldDelete = index == null; - - if (isObject(key)) { - const hash = getHash(key); - if (shouldDelete) { - delete map._objectIndex[hash]; - } else { - map._objectIndex[hash] = index; - } - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - if (shouldDelete) { - delete map._stringIndex[prefixedKey]; - } else { - map._stringIndex[prefixedKey] = index; - } - } else { - if (shouldDelete) { - delete map._otherIndex[prefixedKey]; - } else { - map._otherIndex[prefixedKey] = index; - } - } - } - } - - /** - * Instantiate a map with internal slots. - * - * @param {map} map - */ - function initMap(map) { - // Data structure design inspired by Traceur's Map implementation. - // We maintain an internal array for all the entries. The array is needed - // to remember order. However, to have a reasonable HashMap performance - // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices - // in objects for fast look ups. Indices are split up according to data - // types to avoid collisions. - map._mapData = []; - - // Object index maps from an object "hash" to index. The hash being a unique - // property of our choosing that we associate with the object. Association - // is done by ways of keeping a non-enumerable property on the object. - // Ideally these would be `Object.create(null)` objects but since we're - // trying to support ES3 we'll have to guard against collisions using - // prefixes on the keys rather than rely on null prototype objects. - map._objectIndex = {}; - - // String index maps from strings to index. - map._stringIndex = {}; - - // Numbers, booleans, undefined, and null. - map._otherIndex = {}; - - // Unfortunately we have to support ES3 and cannot have `Map.prototype.size` - // be a getter method but just a regular method. The biggest problem with - // this is safety. Clients can change the size property easily and possibly - // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we - // can do to mitigate use getters and setters in development to disallow - // and issue a warning for changing the `size` property. - if (__DEV__) { - if (isES5) { - // If the `SECRET_SIZE_PROP` property is already defined then we're not - // in the first call to `initMap` (e.g. coming from `map.clear()`) so - // all we need to do is reset the size without defining the properties. - if (hasOwn.call(map, SECRET_SIZE_PROP)) { - map[SECRET_SIZE_PROP] = 0; - } else { - Object.defineProperty(map, SECRET_SIZE_PROP, { - value: 0, - writable: true, - }); - Object.defineProperty(map, 'size', { - set: v => { - console.error( - 'PLEASE FIX ME: You are changing the map size property which ' + - 'should not be writable and will break in production.', - ); - throw new Error('The map size property is not writable.'); - }, - get: () => map[SECRET_SIZE_PROP], - }); - } - - // NOTE: Early return to implement immutable `.size` in DEV. - return; - } - } - - // This is a diviation from the spec. `size` should be a getter on - // `Map.prototype`. However, we have to support IE8. - map.size = 0; - } - - /** - * Check if something is an object. - * - * @param {*} o - * @return {boolean} - */ - function isObject(o) { - return o != null && (typeof o === 'object' || typeof o === 'function'); - } - - /** - * Create an iteration object. - * - * @param {*} value - * @param {boolean} done - * @return {object} - */ - function createIterResultObject(value, done) { - return {value, done}; - } - - // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8. - const isES5 = (function() { - try { - Object.defineProperty({}, 'x', {}); - return true; - } catch (e) { - return false; - } - })(); - - /** - * Check if an object can be extended. - * - * @param {object|array|function|regexp} o - * @return {boolean} - */ - function isExtensible(o) { - if (!isES5) { - return true; - } else { - return Object.isExtensible(o); - } - } - - const getHash = (function() { - const propIsEnumerable = Object.prototype.propertyIsEnumerable; - const hashProperty = '__MAP_POLYFILL_INTERNAL_HASH__'; - let hashCounter = 0; - - const nonExtensibleObjects = []; - const nonExtensibleHashes = []; - - /** - * Get the "hash" associated with an object. - * - * @param {object|array|function|regexp} o - * @return {number} - */ - return function getHash(o) { - if (hasOwn.call(o, hashProperty)) { - return o[hashProperty]; - } - - if (!isES5) { - if ( - hasOwn.call(o, 'propertyIsEnumerable') && - hasOwn.call(o.propertyIsEnumerable, hashProperty) - ) { - return o.propertyIsEnumerable[hashProperty]; - } - } - - if (isExtensible(o)) { - if (isES5) { - Object.defineProperty(o, hashProperty, { - enumerable: false, - writable: false, - configurable: false, - value: ++hashCounter, - }); - return hashCounter; - } - - if (o.propertyIsEnumerable) { - // Since we can't define a non-enumerable property on the object - // we'll hijack one of the less-used non-enumerable properties to - // save our hash on it. Additionally, since this is a function it - // will not show up in `JSON.stringify` which is what we want. - o.propertyIsEnumerable = function() { - return propIsEnumerable.apply(this, arguments); - }; - return (o.propertyIsEnumerable[hashProperty] = ++hashCounter); - } - } - - // If the object is not extensible, fall back to storing it in an - // array and using Array.prototype.indexOf to find it. - let index = nonExtensibleObjects.indexOf(o); - if (index < 0) { - index = nonExtensibleObjects.length; - nonExtensibleObjects[index] = o; - nonExtensibleHashes[index] = ++hashCounter; - } - return nonExtensibleHashes[index]; - }; - })(); - - return Map; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js deleted file mode 100644 index 564f530b9afd8a..00000000000000 --- a/Libraries/vendor/core/Set.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native */ - -'use strict'; - -const Map = require('./Map'); - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const toIterator = require('./toIterator'); - -module.exports = (function(global) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - // These checks are adapted from es6-shim https://fburl.com/34437854 - if (!_shouldPolyfillES6Collection('Set')) { - return global.Set; - } - - /** - * == ES6 Set Collection == - * - * This module is meant to implement a Set collection as described in chapter - * 23.2 of the ES6 specification. - * - * Set objects are collections of unique values. Where values can be any - * JavaScript value. - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- diviations from the spec: - * - * 1. The use of frozen objects as keys. @see Map module for more on this. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var set = new set(iterable); - * - * set.set(value); - * set.has(value); // true - * set.delete(value); // true - * - * var iterator = set.keys(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.entries(); - * iterator.next(); // {value: [value, value], done: false} - * - * set.forEach(function(value, value){ this === thisArg }, thisArg); - * - * set.clear(); // resets set. - */ - - class Set { - /** - * 23.2.1.1 - * - * Takes an optional `iterable` (which is basically any object that - * implements a Symbol.iterator (@@iterator) method). That is a collection - * of values used to instantiate the set. - * - * @param {*} iterable - */ - constructor(iterable) { - if ( - this == null || - (typeof this !== 'object' && typeof this !== 'function') - ) { - throw new TypeError('Wrong set object type.'); - } - - initSet(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - this.add(next.value); - } - } - } - - /** - * 23.2.3.1 - * - * If it doesn't already exist in the collection a `value` is added. - * - * @param {*} value - * @return {set} - */ - add(value) { - this._map.set(value, value); - this.size = this._map.size; - return this; - } - - /** - * 23.2.3.2 - * - * Clears the set. - */ - clear() { - initSet(this); - } - - /** - * 23.2.3.4 - * - * Deletes a `value` from the collection if it exists. - * Returns true if the value was found and deleted and false otherwise. - * - * @param {*} value - * @return {boolean} - */ - delete(value) { - const ret = this._map.delete(value); - this.size = this._map.size; - return ret; - } - - /** - * 23.2.3.5 - * - * Returns an iterator over a collection of [value, value] tuples. - */ - entries() { - return this._map.entries(); - } - - /** - * 23.2.3.6 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {function} callback - */ - forEach(callback) { - const thisArg = arguments[1]; - const it = this._map.keys(); - let next; - while (!(next = it.next()).done) { - callback.call(thisArg, next.value, next.value, this); - } - } - - /** - * 23.2.3.7 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {*} value - * @return {boolean} - */ - has(value) { - return this._map.has(value); - } - - /** - * 23.2.3.7 - * - * Returns an iterator over the colleciton of values. - */ - values() { - return this._map.values(); - } - } - - // 23.2.3.11 - Set.prototype[toIterator.ITERATOR_SYMBOL] = Set.prototype.values; - - // 23.2.3.7 - Set.prototype.keys = Set.prototype.values; - - function initSet(set) { - set._map = new Map(); - set.size = set._map.size; - } - - return Set; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js deleted file mode 100644 index 1ba893c5aebdbe..00000000000000 --- a/Libraries/vendor/core/_shouldPolyfillES6Collection.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @flow strict - */ - -'use strict'; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used. - */ -function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { - const Collection = global[collectionName]; - if (Collection == null) { - return true; - } - - // The iterator protocol depends on `Symbol.iterator`. If a collection is - // implemented, but `Symbol` is not, it's going to break iteration because - // we'll be using custom "@@iterator" instead, which is not implemented on - // native collections. - if (typeof global.Symbol !== 'function') { - return true; - } - - const proto = Collection.prototype; - - // These checks are adapted from es6-shim: https://fburl.com/34437854 - // NOTE: `isCallableWithoutNew` and `!supportsSubclassing` are not checked - // because they make debugging with "break on exceptions" difficult. - return ( - Collection == null || - typeof Collection !== 'function' || - typeof proto.clear !== 'function' || - new Collection().size !== 0 || - typeof proto.keys !== 'function' || - typeof proto.forEach !== 'function' - ); -} - -const cache: {[name: string]: boolean} = {}; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used and caches this result. - * Make sure to make a first call to this function before a corresponding - * property on global was overriden in any way. - */ -function _shouldPolyfillES6Collection(collectionName: string) { - let result = cache[collectionName]; - if (result !== undefined) { - return result; - } - - result = _shouldActuallyPolyfillES6Collection(collectionName); - cache[collectionName] = result; - return result; -} - -module.exports = _shouldPolyfillES6Collection; diff --git a/flow/Map.js b/flow/Map.js deleted file mode 100644 index c8e830529798ff..00000000000000 --- a/flow/Map.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Map. - -declare module 'Map' { - // Use the name "MapPolyfill" so that we don't get confusing error - // messages about "Using Map instead of Map". - declare class MapPolyfill { - @@iterator(): Iterator<[K, V]>; - constructor(_: void): MapPolyfill; - constructor(_: null): MapPolyfill; - constructor( - iterable: Iterable<[Key, Value]>, - ): MapPolyfill; - clear(): void; - delete(key: K): boolean; - entries(): Iterator<[K, V]>; - forEach( - callbackfn: (value: V, index: K, map: MapPolyfill) => mixed, - thisArg?: any, - ): void; - get(key: K): V | void; - has(key: K): boolean; - keys(): Iterator; - set(key: K, value: V): MapPolyfill; - size: number; - values(): Iterator; - } - - declare module.exports: typeof MapPolyfill; -} diff --git a/flow/Set.js b/flow/Set.js deleted file mode 100644 index 64099c2a6028c3..00000000000000 --- a/flow/Set.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @nolint - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Set. - -declare module 'Set' { - // Use the name "SetPolyfill" so that we don't get confusing error - // messages about "Using Set instead of Set". - declare class SetPolyfill { - @@iterator(): Iterator; - constructor(iterable: ?Iterable): void; - add(value: T): SetPolyfill; - clear(): void; - delete(value: T): boolean; - entries(): Iterator<[T, T]>; - forEach( - callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, - thisArg?: any, - ): void; - has(value: T): boolean; - keys(): Iterator; - size: number; - values(): Iterator; - } - - declare module.exports: typeof SetPolyfill; -} From 8e16a60faa6a70c9b5131aa2a4bc388bf342a15e Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 7 Jun 2019 06:35:19 -0700 Subject: [PATCH 132/330] Remove ImageStore JS files from RN open source Summary: This is being removed from RN as part of Lean Core. Reviewed By: rickhanlonii Differential Revision: D15666249 fbshipit-source-id: 00612b999184f216cc3deb72c6b24af359060abe --- Libraries/Image/ImageStore.js | 103 ------------------ Libraries/Image/NativeImageStore.js | 34 ------ .../react-native-implementation.js | 24 ++-- 3 files changed, 14 insertions(+), 147 deletions(-) delete mode 100644 Libraries/Image/ImageStore.js delete mode 100644 Libraries/Image/NativeImageStore.js diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js deleted file mode 100644 index 7d6e7be5d6faac..00000000000000 --- a/Libraries/Image/ImageStore.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; - -import NativeImageStore from './NativeImageStore'; - -const Platform = require('../Utilities/Platform'); - -const warnOnce = require('../Utilities/warnOnce'); - -function warnUnimplementedMethod(methodName: string): void { - warnOnce( - `imagestore-${methodName}`, - `react-native: ImageStore.${methodName}() is not implemented on ${ - Platform.OS - }`, - ); -} - -class ImageStore { - /** - * Check if the ImageStore contains image data for the specified URI. - * @platform ios - */ - static hasImageForTag(uri: string, callback: (hasImage: boolean) => void) { - if (NativeImageStore.hasImageForTag) { - NativeImageStore.hasImageForTag(uri, callback); - } else { - warnUnimplementedMethod('hasImageForTag'); - } - } - - /** - * Delete an image from the ImageStore. Images are stored in memory and - * must be manually removed when you are finished with them, otherwise they - * will continue to use up RAM until the app is terminated. It is safe to - * call `removeImageForTag()` without first calling `hasImageForTag()`, it - * will simply fail silently. - * @platform ios - */ - static removeImageForTag(uri: string) { - if (NativeImageStore.removeImageForTag) { - NativeImageStore.removeImageForTag(uri); - } else { - warnUnimplementedMethod('removeImageForTag'); - } - } - - /** - * Stores a base64-encoded image in the ImageStore, and returns a URI that - * can be used to access or display the image later. Images are stored in - * memory only, and must be manually deleted when you are finished with - * them by calling `removeImageForTag()`. - * - * Note that it is very inefficient to transfer large quantities of binary - * data between JS and native code, so you should avoid calling this more - * than necessary. - * @platform ios - */ - static addImageFromBase64( - base64ImageData: string, - success: (uri: string) => void, - failure: (error: any) => void, - ) { - if (NativeImageStore.addImageFromBase64) { - NativeImageStore.addImageFromBase64(base64ImageData, success, failure); - } else { - warnUnimplementedMethod('addImageFromBase64'); - } - } - - /** - * Retrieves the base64-encoded data for an image in the ImageStore. If the - * specified URI does not match an image in the store, the failure callback - * will be called. - * - * Note that it is very inefficient to transfer large quantities of binary - * data between JS and native code, so you should avoid calling this more - * than necessary. To display an image in the ImageStore, you can just pass - * the URI to an `` component; there is no need to retrieve the - * base64 data. - */ - static getBase64ForTag( - uri: string, - success: (base64ImageData: string) => void, - failure: (error: any) => void, - ) { - if (NativeImageStore.getBase64ForTag) { - NativeImageStore.getBase64ForTag(uri, success, failure); - } else { - warnUnimplementedMethod('getBase64ForTag'); - } - } -} - -module.exports = ImageStore; diff --git a/Libraries/Image/NativeImageStore.js b/Libraries/Image/NativeImageStore.js deleted file mode 100644 index 0bc4948f1fb0a8..00000000000000 --- a/Libraries/Image/NativeImageStore.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -import type {TurboModule} from '../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - // Common - +getBase64ForTag: ( - uri: string, - success: (base64ImageData: string) => void, - failure: (error: Object) => void, - ) => void; - - // iOS-only - +hasImageForTag: (uri: string, callback: (hasImage: boolean) => void) => void; - +removeImageForTag: (uri: string) => void; - +addImageFromBase64: ( - base64ImageData: string, - success: (uri: string) => void, - failure: (error: Object) => void, - ) => void; -} - -export default TurboModuleRegistry.getEnforcing('ImageStoreManager'); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index d3602050e7f760..1fb35b409b6bdd 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -61,16 +61,6 @@ module.exports = { ); return require('../Image/ImageEditor'); }, - get ImageStore() { - warnOnce( - 'imagestore-deprecation', - 'ImageStore is deprecated and will be removed in a future release. ' + - 'To get a base64-encoded string from a local image use either of the following third-party libraries:' + - "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" + - "* react-native-fs: `readFile(filepath, 'base64')`", - ); - return require('../Image/ImageStore'); - }, get InputAccessoryView() { return require('../Components/TextInput/InputAccessoryView'); }, @@ -413,4 +403,18 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access ImageStore. + Object.defineProperty(module.exports, 'ImageStore', { + configurable: true, + get() { + invariant( + false, + 'ImageStore has been removed from React Native. ' + + 'To get a base64-encoded string from a local image use either of the following third-party libraries:' + + "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" + + "* react-native-fs: `readFile(filepath, 'base64')`", + ); + }, + }); } From 2b262ec78b48a7aaa164125cadc4f0593b71fdf3 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 7 Jun 2019 08:04:52 -0700 Subject: [PATCH 133/330] Back out "[RN][TurboModule] Enable TurboModules for FB4A" Summary: Original commit changeset: e295dafdab7a I'm backing this out because it's broken Catalyst. The fixes are in D15711539, but it could take some time to review and land them. Reviewed By: rickhanlonii Differential Revision: D15714896 fbshipit-source-id: c2c555a52d3d140dfdea7d54ccd8d3102c22a1c6 --- .../main/java/com/facebook/react/bridge/BaseJavaModule.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index da1d60f94f0897..04ca7a91c74969 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -67,9 +67,4 @@ public void onCatalystInstanceDestroy() { public boolean hasConstants() { return false; } - - // Cleanup Logic for TurboModuels - public void invalidate() { - // Do nothing - } } From 5751035f648879c6ed84293270ffc4902ee64d6e Mon Sep 17 00:00:00 2001 From: Aditya Sharat Date: Fri, 7 Jun 2019 09:22:17 -0700 Subject: [PATCH 134/330] Adds check to unset a YogaNode's parent during reconciliation. Summary: Adds check to unset a YogaNode's parent during reconciliation. Reviewed By: davidaurelio Differential Revision: D15714899 fbshipit-source-id: 6e2c2a28106574d062fec722c9a051acea87d0b6 --- ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java | 2 ++ .../src/main/java/com/facebook/yoga/YogaNodeJNIBase.java | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index a01a0bdde49ddb..9a8e19663fd1a0 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -42,6 +42,8 @@ public static YogaNode create(YogaConfig config) { @Nullable public abstract YogaNode getOwner(); + public abstract void unsetOwner(); + /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java index c48162f4a470d6..0e1f68c8e97a35 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -137,6 +137,11 @@ public YogaNodeJNIBase getOwner() { return mOwner; } + @Override + public void unsetOwner() { + mOwner = null; + } + /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable From 63ed75fe9e902f0c9be2417ff977b5882630f453 Mon Sep 17 00:00:00 2001 From: Chris Blappert Date: Fri, 7 Jun 2019 11:35:12 -0700 Subject: [PATCH 135/330] Fix comment Reviewed By: yungsters Differential Revision: D15585102 fbshipit-source-id: c6809d6600d66559e5dd9fa054e31e5e38744af3 --- Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index b39983d5e6062d..c4d00585437137 100644 --- a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -66,7 +66,6 @@ function processEventTypes( * Registers a native view/component by name. * A callback is provided to load the view config from UIManager. * The callback is deferred until the view is actually rendered. - * This is done to avoid causing Prepack deopts. */ exports.register = function(name: string, callback: ViewConfigGetter): string { invariant( From a19cfc227323910991eff9071f05f47140f709db Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 7 Jun 2019 12:00:01 -0700 Subject: [PATCH 136/330] Fabric: Scheduler-specific dependencies were moved to a separate class from ContextContainer Summary: ContextContainer should contain only product/component-specific dependencies and stay unchanged during VM/Scheduler reloading. Reviewed By: JoshuaGross Differential Revision: D15636656 fbshipit-source-id: fe5de1b6c92f659b28d31eba901c04c5b23fe1d1 --- React/Fabric/RCTScheduler.h | 4 +- React/Fabric/RCTScheduler.mm | 5 +- React/Fabric/RCTSurfacePresenter.mm | 57 +++++++++++-------- .../com/facebook/react/fabric/jni/Binding.cpp | 16 +++--- ReactCommon/fabric/uimanager/Scheduler.cpp | 24 +++----- ReactCommon/fabric/uimanager/Scheduler.h | 5 +- .../fabric/uimanager/SchedulerToolbox.cpp | 6 ++ .../fabric/uimanager/SchedulerToolbox.h | 47 +++++++++++++++ 8 files changed, 108 insertions(+), 56 deletions(-) create mode 100644 ReactCommon/fabric/uimanager/SchedulerToolbox.cpp create mode 100644 ReactCommon/fabric/uimanager/SchedulerToolbox.h diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index bebdaedcfe827f..a48ef1f0592cfd 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -14,6 +14,7 @@ #import #import #import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -36,8 +37,7 @@ NS_ASSUME_NONNULL_BEGIN @property (atomic, weak, nullable) id delegate; -- (instancetype)initWithContextContainer:(facebook::react::ContextContainer::Shared)contextContatiner - componentRegistryFactory:(facebook::react::ComponentRegistryFactory)componentRegistryFactory; +- (instancetype)initWithToolbox:(facebook::react::SchedulerToolbox)toolbox; - (void)startSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId moduleName:(NSString *)moduleName diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 185e012fed60d2..a21051f04fbce5 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -43,12 +43,11 @@ @implementation RCTScheduler { std::shared_ptr _delegateProxy; } -- (instancetype)initWithContextContainer:(ContextContainer::Shared)contextContainer - componentRegistryFactory:(ComponentRegistryFactory)componentRegistryFactory +- (instancetype)initWithToolbox:(facebook::react::SchedulerToolbox)toolbox { if (self = [super init]) { _delegateProxy = std::make_shared((__bridge void *)self); - _scheduler = std::make_shared(contextContainer, componentRegistryFactory); + _scheduler = std::make_shared(toolbox); _scheduler->setDelegate(_delegateProxy.get()); } diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 06c8c5cab728db..0892963a39bcd2 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -31,6 +31,7 @@ #import #import #import +#import #import #import @@ -203,8 +204,22 @@ - (RCTScheduler *)_scheduler createComponentDescriptorRegistryWithParameters:{eventDispatcher, contextContainer}]; }; - _scheduler = [[RCTScheduler alloc] initWithContextContainer:self.contextContainer - componentRegistryFactory:componentRegistryFactory]; + auto runtimeExecutor = [self _runtimeExecutor]; + + auto toolbox = SchedulerToolbox{}; + toolbox.contextContainer = _contextContainer; + toolbox.componentRegistryFactory = componentRegistryFactory; + toolbox.runtimeExecutor = runtimeExecutor; + + toolbox.synchronousEventBeatFactory = [runtimeExecutor]() { + return std::make_unique(runtimeExecutor); + }; + + toolbox.asynchronousEventBeatFactory = [runtimeExecutor]() { + return std::make_unique(runtimeExecutor); + }; + + _scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox]; _scheduler.delegate = self; return _scheduler; @@ -212,18 +227,8 @@ - (RCTScheduler *)_scheduler @synthesize contextContainer = _contextContainer; -- (ContextContainer::Shared)contextContainer +- (RuntimeExecutor)_runtimeExecutor { - std::lock_guard lock(_contextContainerMutex); - - if (_contextContainer) { - return _contextContainer; - } - - _contextContainer = std::make_shared(); - - _contextContainer->registerInstance(_reactNativeConfig, "ReactNativeConfig"); - auto messageQueueThread = _batchedBridge.jsMessageThread; if (messageQueueThread) { // Make sure initializeBridge completed @@ -239,20 +244,25 @@ - (RCTScheduler *)_scheduler [((RCTCxxBridge *)_batchedBridge) invokeAsync:[runtime, callback = std::move(callback)]() { callback(*runtime); }]; }; - EventBeatFactory synchronousBeatFactory = [runtimeExecutor]() { - return std::make_unique(runtimeExecutor); - }; - - EventBeatFactory asynchronousBeatFactory = [runtimeExecutor]() { - return std::make_unique(runtimeExecutor); - }; + return runtimeExecutor; +} - _contextContainer->registerInstance(synchronousBeatFactory, "synchronous"); - _contextContainer->registerInstance(asynchronousBeatFactory, "asynchronous"); +- (ContextContainer::Shared)contextContainer +{ + std::lock_guard lock(_contextContainerMutex); - _contextContainer->registerInstance(runtimeExecutor, "runtime-executor"); + if (_contextContainer) { + return _contextContainer; + } + _contextContainer = std::make_shared(); + // Please do not add stuff here; `SurfacePresenter` must not alter `ContextContainer`. + // Those two pieces eventually should be moved out there: + // * `RCTImageLoader` should be moved to `RNImageComponentView`. + // * `ReactNativeConfig` should be set by outside product code. + _contextContainer->registerInstance(_reactNativeConfig, "ReactNativeConfig"); _contextContainer->registerInstance(wrapManagedObject([_bridge imageLoader]), "RCTImageLoader"); + return _contextContainer; } @@ -390,7 +400,6 @@ - (void)handleBridgeWillReloadNotification:(NSNotification *)notification { std::lock_guard lock(_schedulerMutex); _scheduler = nil; - _contextContainer = nil; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index e38edd549d76bf..9d2a6c12cac6f4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -136,16 +137,15 @@ void Binding::installFabricUIManager( std::shared_ptr config = std::make_shared(reactNativeConfig); contextContainer->registerInstance(config, "ReactNativeConfig"); - contextContainer->registerInstance( - synchronousBeatFactory, "synchronous"); - contextContainer->registerInstance( - asynchronousBeatFactory, "asynchronous"); contextContainer->registerInstance(javaUIManager_, "FabricUIManager"); - contextContainer->registerInstance(runtimeExecutor, "runtime-executor"); - - scheduler_ = std::make_shared( - contextContainer, componentsRegistry->buildRegistryFunction); + auto toolbox = SchedulerToolbox{}; + toolbox.contextContainer = contextContainer; + toolbox.componentRegistryFactory = componentsRegistry->buildRegistryFunction; + toolbox.runtimeExecutor = runtimeExecutor; + toolbox.synchronousEventBeatFactory = synchronousBeatFactory; + toolbox.asynchronousEventBeatFactory = asynchronousBeatFactory; + scheduler_ = std::make_shared(toolbox); scheduler_->setDelegate(this); } diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index aab1121d9341e8..1eb3fcd969f55c 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -18,19 +18,11 @@ namespace facebook { namespace react { -Scheduler::Scheduler( - ContextContainer::Shared const &contextContainer, - ComponentRegistryFactory buildRegistryFunction) { - const auto asynchronousEventBeatFactory = - contextContainer->getInstance("asynchronous"); - const auto synchronousEventBeatFactory = - contextContainer->getInstance("synchronous"); - - runtimeExecutor_ = - contextContainer->getInstance("runtime-executor"); +Scheduler::Scheduler(SchedulerToolbox schedulerToolbox) { + runtimeExecutor_ = schedulerToolbox.runtimeExecutor; reactNativeConfig_ = - contextContainer->getInstance>( + schedulerToolbox.contextContainer->getInstance>( "ReactNativeConfig"); auto uiManager = std::make_unique(); @@ -55,11 +47,11 @@ Scheduler::Scheduler( auto eventDispatcher = std::make_shared( eventPipe, statePipe, - synchronousEventBeatFactory, - asynchronousEventBeatFactory); + schedulerToolbox.synchronousEventBeatFactory, + schedulerToolbox.asynchronousEventBeatFactory); - componentDescriptorRegistry_ = - buildRegistryFunction(eventDispatcher, contextContainer); + componentDescriptorRegistry_ = schedulerToolbox.componentRegistryFactory( + eventDispatcher, schedulerToolbox.contextContainer); rootComponentDescriptor_ = std::make_unique(eventDispatcher); @@ -72,7 +64,7 @@ Scheduler::Scheduler( UIManagerBinding::install(runtime, uiManagerBinding_); }); - contextContainer->registerInstance( + schedulerToolbox.contextContainer->registerInstance( std::weak_ptr( componentDescriptorRegistry_), "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE"); diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index ea4469ac3ed767..6cd4322501cbd0 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -31,9 +32,7 @@ namespace react { */ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate { public: - Scheduler( - ContextContainer::Shared const &contextContainer, - ComponentRegistryFactory buildRegistryFunction); + Scheduler(SchedulerToolbox schedulerToolbox); ~Scheduler(); #pragma mark - Surface Management diff --git a/ReactCommon/fabric/uimanager/SchedulerToolbox.cpp b/ReactCommon/fabric/uimanager/SchedulerToolbox.cpp new file mode 100644 index 00000000000000..c02009d00d3043 --- /dev/null +++ b/ReactCommon/fabric/uimanager/SchedulerToolbox.cpp @@ -0,0 +1,6 @@ +// Copyright (c) Facebook, Inc. and its affiliates. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "SchedulerToolbox.h" diff --git a/ReactCommon/fabric/uimanager/SchedulerToolbox.h b/ReactCommon/fabric/uimanager/SchedulerToolbox.h new file mode 100644 index 00000000000000..083609c6ad9c86 --- /dev/null +++ b/ReactCommon/fabric/uimanager/SchedulerToolbox.h @@ -0,0 +1,47 @@ +// Copyright (c) Facebook, Inc. and its affiliates. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * Contains all external dependencies of Scheduler. + * Copyable. + */ +struct SchedulerToolbox final { + /* + * Represents general purpose DI container for product components/needs. + * Must not be `nullptr`. + */ + ContextContainer::Shared contextContainer; + + /* + * Represents externally managed, lazily available collection of components. + */ + ComponentRegistryFactory componentRegistryFactory; + + /* + * Represents running JavaScript VM and associated execution queue. + */ + RuntimeExecutor runtimeExecutor; + + /* + * Asynchronous & synchronous event beats. + * Represent connections with the platform-specific run loops and general + * purpose background queue. + */ + EventBeatFactory asynchronousEventBeatFactory; + EventBeatFactory synchronousEventBeatFactory; +}; + +} // namespace react +} // namespace facebook From 205de0538cd16943bfe1cb8c35bb8005310e1600 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 7 Jun 2019 12:00:01 -0700 Subject: [PATCH 137/330] Fabric: New names for ContextContainer methods Summary: ... and slighly new behaviour for one of them. The method does nothing if given `key` already exists in the container. This diff finishes the transition of ContextContainer from an internal bag of things with unclear yet ownership into a legit dedicated dependency injection container for the product code. The original names of methods imply that the container can have only one object of a given type which is no longer true. The new API is much more generic and idiomatic to C++, it mimics `std:map` API which is intuitive to anyone who familiar with C++ containers. Besides the naming, `insert` method changed the semantic a bit; now it does nothing in case of inserting an object with a key that already exists. That might seem counterintuitive for "normal" people, but C++ has some wired reasons for that and, hopefully, it's expected behavior in the C++ community. Fun fact: We need this to fix hot-reload. Reviewed By: sahrens Differential Revision: D15681736 fbshipit-source-id: 194f342528446a911eaf072ba3a94a5d8af3cb52 --- React/Fabric/RCTSurfacePresenter.mm | 4 ++-- .../java/com/facebook/react/fabric/jni/Binding.cpp | 4 ++-- .../platform/android/SliderMeasurementsManager.cpp | 3 +-- .../fabric/imagemanager/platform/ios/ImageManager.mm | 2 +- .../platform/android/TextLayoutManager.cpp | 3 +-- ReactCommon/fabric/uimanager/Scheduler.cpp | 10 +++++----- ReactCommon/utils/ContextContainer.h | 10 ++++------ 7 files changed, 16 insertions(+), 20 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 0892963a39bcd2..edb6972ea2d6c3 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -260,8 +260,8 @@ - (RuntimeExecutor)_runtimeExecutor // Those two pieces eventually should be moved out there: // * `RCTImageLoader` should be moved to `RNImageComponentView`. // * `ReactNativeConfig` should be set by outside product code. - _contextContainer->registerInstance(_reactNativeConfig, "ReactNativeConfig"); - _contextContainer->registerInstance(wrapManagedObject([_bridge imageLoader]), "RCTImageLoader"); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); + _contextContainer->insert("RCTImageLoader", wrapManagedObject([_bridge imageLoader])); return _contextContainer; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 9d2a6c12cac6f4..80295048094023 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -136,8 +136,8 @@ void Binding::installFabricUIManager( std::shared_ptr config = std::make_shared(reactNativeConfig); - contextContainer->registerInstance(config, "ReactNativeConfig"); - contextContainer->registerInstance(javaUIManager_, "FabricUIManager"); + contextContainer->insert("ReactNativeConfig", config); + contextContainer->insert("FabricUIManager", javaUIManager_); auto toolbox = SchedulerToolbox{}; toolbox.contextContainer = contextContainer; diff --git a/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp b/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp index ca6e6808f2cb91..c44288caefc65f 100644 --- a/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp +++ b/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp @@ -26,8 +26,7 @@ Size SliderMeasurementsManager::measure( } const jni::global_ref &fabricUIManager = - contextContainer_->getInstance>( - "FabricUIManager"); + contextContainer_->at>("FabricUIManager"); static auto measure = jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") diff --git a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm index d5c64f5f06b3cf..e3b4074eb24a59 100644 --- a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm +++ b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm @@ -18,7 +18,7 @@ ImageManager::ImageManager(ContextContainer::Shared const &contextContainer) { RCTImageLoader *imageLoader = - (RCTImageLoader *)unwrapManagedObject(contextContainer->getInstance>("RCTImageLoader")); + (RCTImageLoader *)unwrapManagedObject(contextContainer->at>("RCTImageLoader")); self_ = (__bridge_retained void *)[[RCTImageManager alloc] initWithImageLoader:imageLoader]; } diff --git a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp index b6e04fe311e172..46e9fb6e68ff47 100644 --- a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp +++ b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp @@ -27,8 +27,7 @@ Size TextLayoutManager::measure( ParagraphAttributes paragraphAttributes, LayoutConstraints layoutConstraints) const { const jni::global_ref &fabricUIManager = - contextContainer_->getInstance>( - "FabricUIManager"); + contextContainer_->at>("FabricUIManager"); static auto measure = jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 1eb3fcd969f55c..9b78bdc649eb38 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -22,8 +22,8 @@ Scheduler::Scheduler(SchedulerToolbox schedulerToolbox) { runtimeExecutor_ = schedulerToolbox.runtimeExecutor; reactNativeConfig_ = - schedulerToolbox.contextContainer->getInstance>( - "ReactNativeConfig"); + schedulerToolbox.contextContainer + ->at>("ReactNativeConfig"); auto uiManager = std::make_unique(); auto &uiManagerRef = *uiManager; @@ -64,10 +64,10 @@ Scheduler::Scheduler(SchedulerToolbox schedulerToolbox) { UIManagerBinding::install(runtime, uiManagerBinding_); }); - schedulerToolbox.contextContainer->registerInstance( + schedulerToolbox.contextContainer->insert( + "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE", std::weak_ptr( - componentDescriptorRegistry_), - "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE"); + componentDescriptorRegistry_)); } Scheduler::~Scheduler() { diff --git a/ReactCommon/utils/ContextContainer.h b/ReactCommon/utils/ContextContainer.h index 4e5a653607ba8d..4889a43bc7b716 100644 --- a/ReactCommon/utils/ContextContainer.h +++ b/ReactCommon/utils/ContextContainer.h @@ -27,6 +27,7 @@ class ContextContainer final { /* * Registers an instance of the particular type `T` in the container * using the provided `key`. Only one instance can be registered per key. + * The method does nothing if given `key` already exists in the container. * * Convention is to use the plain base class name for the key, so for * example if the type `T` is `std::shared_ptr`, @@ -35,12 +36,9 @@ class ContextContainer final { *`EmptyReactNativeConfig`. */ template - void registerInstance(T const &instance, std::string const &key) const { + void insert(std::string const &key, T const &instance) const { std::unique_lock lock(mutex_); - assert( - instances_.find(key) == instances_.end() && - "ContextContainer already had instance for given key."); instances_.insert({key, std::make_shared(instance)}); #ifndef NDEBUG @@ -54,7 +52,7 @@ class ContextContainer final { * Throws an exception if the instance could not be found. */ template - T getInstance(std::string const &key) const { + T at(std::string const &key) const { std::shared_lock lock(mutex_); assert( @@ -72,7 +70,7 @@ class ContextContainer final { * Returns an empty optional if the instance could not be found. */ template - better::optional findInstance(std::string const &key) const { + better::optional find(std::string const &key) const { std::shared_lock lock(mutex_); auto iterator = instances_.find(key); From 12c09a2d6cf20e3591c19986ce24924ae5f63fd3 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 7 Jun 2019 12:00:01 -0700 Subject: [PATCH 138/330] Fabric: Bunch of code style changes Summary: Code style only. Reviewed By: sahrens Differential Revision: D15681737 fbshipit-source-id: 24cc2e9b9434448026e7cb3cfd274ea14bd835a2 --- React/Fabric/RCTSurfacePresenter.mm | 48 +++++--------- .../imagemanager/platform/ios/ImageManager.mm | 6 +- ReactCommon/fabric/uimanager/Scheduler.cpp | 66 +++++++++---------- 3 files changed, 53 insertions(+), 67 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index edb6972ea2d6c3..adc049828ad2cb 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -7,10 +7,10 @@ #import "RCTSurfacePresenter.h" +#import +#import #import #import -#import -#import #import #import @@ -36,8 +36,8 @@ #import #import "MainRunLoopEventBeat.h" -#import "RuntimeEventBeat.h" #import "RCTConversions.h" +#import "RuntimeEventBeat.h" using namespace facebook::react; @@ -52,9 +52,10 @@ @interface RCTSurfacePresenter () _reactNativeConfig; @@ -123,8 +124,7 @@ - (void)unregisterSurface:(RCTFabricSurface *)surface [_surfaceRegistry unregisterSurface:surface]; } -- (void)setProps:(NSDictionary *)props - surface:(RCTFabricSurface *)surface +- (void)setProps:(NSDictionary *)props surface:(RCTFabricSurface *)surface { // This implementation is suboptimal indeed but still better than nothing for now. [self _stopSurface:surface]; @@ -140,32 +140,22 @@ - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize surface:(RCTFabricSurface *)surface { - LayoutContext layoutContext = { - .pointScaleFactor = RCTScreenScale() - }; + LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()}; - LayoutConstraints layoutConstraints = { - .minimumSize = RCTSizeFromCGSize(minimumSize), - .maximumSize = RCTSizeFromCGSize(maximumSize) - }; + LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(minimumSize), + .maximumSize = RCTSizeFromCGSize(maximumSize)}; return [self._scheduler measureSurfaceWithLayoutConstraints:layoutConstraints layoutContext:layoutContext surfaceId:surface.rootTag]; } -- (void)setMinimumSize:(CGSize)minimumSize - maximumSize:(CGSize)maximumSize - surface:(RCTFabricSurface *)surface +- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize surface:(RCTFabricSurface *)surface { - LayoutContext layoutContext = { - .pointScaleFactor = RCTScreenScale() - }; + LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()}; - LayoutConstraints layoutConstraints = { - .minimumSize = RCTSizeFromCGSize(minimumSize), - .maximumSize = RCTSizeFromCGSize(maximumSize) - }; + LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(minimumSize), + .maximumSize = RCTSizeFromCGSize(maximumSize)}; [self._scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints layoutContext:layoutContext @@ -274,14 +264,10 @@ - (void)_startSurface:(RCTFabricSurface *)surface tag:surface.rootTag]; }); - LayoutContext layoutContext = { - .pointScaleFactor = RCTScreenScale() - }; + LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()}; - LayoutConstraints layoutConstraints = { - .minimumSize = RCTSizeFromCGSize(surface.minimumSize), - .maximumSize = RCTSizeFromCGSize(surface.maximumSize) - }; + LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(surface.minimumSize), + .maximumSize = RCTSizeFromCGSize(surface.maximumSize)}; [self._scheduler startSurfaceWithSurfaceId:surface.rootTag moduleName:surface.moduleName diff --git a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm index e3b4074eb24a59..148b95fe1663ce 100644 --- a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm +++ b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm @@ -22,12 +22,14 @@ self_ = (__bridge_retained void *)[[RCTImageManager alloc] initWithImageLoader:imageLoader]; } -ImageManager::~ImageManager() { +ImageManager::~ImageManager() +{ CFRelease(self_); self_ = nullptr; } -ImageRequest ImageManager::requestImage(const ImageSource &imageSource) const { +ImageRequest ImageManager::requestImage(const ImageSource &imageSource) const +{ RCTImageManager *imageManager = (__bridge RCTImageManager *)self_; return [imageManager requestImage:imageSource]; } diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 9b78bdc649eb38..1029584f9fa65a 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -138,25 +138,24 @@ void Scheduler::renderTemplateToSurface( void Scheduler::stopSurface(SurfaceId surfaceId) const { SystraceSection s("Scheduler::stopSurface"); - shadowTreeRegistry_.visit( - surfaceId, [](const ShadowTree &shadowTree) { - // As part of stopping the Surface, we have to commit an empty tree. - return shadowTree.tryCommit( - [&](const SharedRootShadowNode &oldRootShadowNode) { - return std::make_shared( - *oldRootShadowNode, - ShadowNodeFragment{ - /* .tag = */ ShadowNodeFragment::tagPlaceholder(), - /* .surfaceId = */ - ShadowNodeFragment::surfaceIdPlaceholder(), - /* .props = */ ShadowNodeFragment::propsPlaceholder(), - /* .eventEmitter = */ - ShadowNodeFragment::eventEmitterPlaceholder(), - /* .children = */ - ShadowNode::emptySharedShadowNodeSharedList(), - }); - }); - }); + shadowTreeRegistry_.visit(surfaceId, [](const ShadowTree &shadowTree) { + // As part of stopping the Surface, we have to commit an empty tree. + return shadowTree.tryCommit( + [&](const SharedRootShadowNode &oldRootShadowNode) { + return std::make_shared( + *oldRootShadowNode, + ShadowNodeFragment{ + /* .tag = */ ShadowNodeFragment::tagPlaceholder(), + /* .surfaceId = */ + ShadowNodeFragment::surfaceIdPlaceholder(), + /* .props = */ ShadowNodeFragment::propsPlaceholder(), + /* .eventEmitter = */ + ShadowNodeFragment::eventEmitterPlaceholder(), + /* .children = */ + ShadowNode::emptySharedShadowNodeSharedList(), + }); + }); + }); auto shadowTree = shadowTreeRegistry_.remove(surfaceId); shadowTree->setDelegate(nullptr); @@ -232,21 +231,20 @@ void Scheduler::uiManagerDidFinishTransaction( const SharedShadowNodeUnsharedList &rootChildNodes) { SystraceSection s("Scheduler::uiManagerDidFinishTransaction"); - shadowTreeRegistry_.visit( - surfaceId, [&](const ShadowTree &shadowTree) { - shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { - return std::make_shared( - *oldRootShadowNode, - ShadowNodeFragment{ - /* .tag = */ ShadowNodeFragment::tagPlaceholder(), - /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), - /* .props = */ ShadowNodeFragment::propsPlaceholder(), - /* .eventEmitter = */ - ShadowNodeFragment::eventEmitterPlaceholder(), - /* .children = */ rootChildNodes, - }); - }); - }); + shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) { + shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { + return std::make_shared( + *oldRootShadowNode, + ShadowNodeFragment{ + /* .tag = */ ShadowNodeFragment::tagPlaceholder(), + /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), + /* .props = */ ShadowNodeFragment::propsPlaceholder(), + /* .eventEmitter = */ + ShadowNodeFragment::eventEmitterPlaceholder(), + /* .children = */ rootChildNodes, + }); + }); + }); } void Scheduler::uiManagerDidCreateShadowNode( From 886fb501bdbd875dcc424723d30ad325e367b1f1 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:55 -0700 Subject: [PATCH 139/330] RN Codegen] Add registerGeneratedViewConfig Summary: This diff updated the format of generated view configs so that they don't need to spread View props into every config, by adding a new registerGeneratedConfig function which will spread them instead This is a bit of a cleanup of the generated output but is primarily so that the view config babel plugin will not need to rely on object spreading or object.assigns Reviewed By: TheSavior, cpojer Differential Revision: D15517199 fbshipit-source-id: 08e575578177bad12d40ee3dcad9381974b6466d --- .../PullToRefreshViewNativeViewConfig.js | 19 +- .../Utilities/registerGeneratedViewConfig.js | 70 ++++ .../src/generators/GenerateViewConfigJs.js | 53 +-- .../GenerateViewConfigJs-test.js.snap | 341 ++---------------- 4 files changed, 106 insertions(+), 377 deletions(-) create mode 100644 Libraries/Utilities/registerGeneratedViewConfig.js diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js index f76c8e02dd2140..e6157a13b05f79 100644 --- a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js @@ -10,17 +10,12 @@ 'use strict'; -const ReactNativeViewConfigRegistry = require('../../Renderer/shims/ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('../View/ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('../../Utilities/verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('../../Utilities/registerGeneratedViewConfig'); const PullToRefreshViewViewConfig = { uiViewClassName: 'PullToRefreshView', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topRefresh: { phasedRegistrationNames: { captured: 'onRefreshCapture', @@ -29,12 +24,7 @@ const PullToRefreshViewViewConfig = { }, }, - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, tintColor: { process: require('../../StyleSheet/processColor') }, titleColor: { process: require('../../StyleSheet/processColor') }, title: true, @@ -43,11 +33,6 @@ const PullToRefreshViewViewConfig = { }, }; -verifyComponentAttributeEquivalence('PullToRefreshView', PullToRefreshViewViewConfig); - -ReactNativeViewConfigRegistry.register( - 'PullToRefreshView', - () => PullToRefreshViewViewConfig, -); +registerGeneratedViewConfig('PullToRefreshView', PullToRefreshViewViewConfig); module.exports = 'PullToRefreshView'; diff --git a/Libraries/Utilities/registerGeneratedViewConfig.js b/Libraries/Utilities/registerGeneratedViewConfig.js new file mode 100644 index 00000000000000..ee73030867845c --- /dev/null +++ b/Libraries/Utilities/registerGeneratedViewConfig.js @@ -0,0 +1,70 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +const ReactNativeViewConfigRegistry = require('../Renderer/shims/ReactNativeViewConfigRegistry'); +const ReactNativeViewViewConfig = require('../Components/View/ReactNativeViewViewConfig'); +const verifyComponentAttributeEquivalence = require('./verifyComponentAttributeEquivalence'); + +type GeneratedViewConfig = { + uiViewClassName: string, + bubblingEventTypes?: $ReadOnly<{ + [eventName: string]: $ReadOnly<{| + phasedRegistrationNames: $ReadOnly<{| + captured: string, + bubbled: string, + |}>, + |}>, + }>, + directEventTypes?: $ReadOnly<{ + [eventName: string]: $ReadOnly<{| + registrationName: string, + |}>, + }>, + validAttributes?: { + [propName: string]: + | true + | $ReadOnly<{| + diff?: (arg1: any, arg2: any) => boolean, + process?: (arg1: any) => any, + |}>, + }, +}; + +function registerGeneratedViewConfig( + componentName: string, + viewConfig: GeneratedViewConfig, +) { + const mergedViewConfig = { + uiViewClassName: viewConfig.uiViewClassName, + Commands: {}, + bubblingEventTypes: { + ...ReactNativeViewViewConfig.bubblingEventTypes, + ...(viewConfig.bubblingEventTypes || {}), + }, + directEventTypes: { + ...ReactNativeViewViewConfig.directEventTypes, + ...(viewConfig.directEventTypes || {}), + }, + validAttributes: { + ...ReactNativeViewViewConfig.validAttributes, + ...(viewConfig.validAttributes || {}), + }, + }; + + ReactNativeViewConfigRegistry.register(componentName, () => { + verifyComponentAttributeEquivalence(componentName, mergedViewConfig); + + return mergedViewConfig; + }); +} + +module.exports = registerGeneratedViewConfig; diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index d5e1583ea2bccc..d5f8cde857f88a 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -87,12 +87,7 @@ function getReactDiffProcessValue(typeAnnotation) { const componentTemplate = ` const ::_COMPONENT_NAME_::ViewConfig = VIEW_CONFIG; -verifyComponentAttributeEquivalence('::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', ::_COMPONENT_NAME_::ViewConfig); - -ReactNativeViewConfigRegistry.register( - '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', - () => ::_COMPONENT_NAME_::ViewConfig, -); +registerGeneratedViewConfig('::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', ::_COMPONENT_NAME_::ViewConfig); module.exports = '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_:: `.trim(); @@ -159,38 +154,13 @@ function buildViewConfig( const componentProps = component.props; const componentEvents = component.events; - let viewAttributes = null; - let viewEvents = null; - let viewDirectEvents = null; - component.extendsProps.forEach(extendProps => { switch (extendProps.type) { case 'ReactNativeBuiltInType': switch (extendProps.knownTypeName) { case 'ReactNativeCoreViewProps': imports.add( - "const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig');", - ); - - viewAttributes = j.spreadProperty( - j.memberExpression( - j.identifier('ReactNativeViewViewConfig'), - j.identifier('validAttributes'), - ), - ); - - viewEvents = j.spreadProperty( - j.memberExpression( - j.identifier('ReactNativeViewViewConfig'), - j.identifier('bubblingEventTypes'), - ), - ); - - viewDirectEvents = j.spreadProperty( - j.memberExpression( - j.identifier('ReactNativeViewViewConfig'), - j.identifier('directEventTypes'), - ), + "const registerGeneratedViewConfig = require('registerGeneratedViewConfig');", ); return; @@ -205,7 +175,6 @@ function buildViewConfig( }); const validAttributes = j.objectExpression([ - viewAttributes, ...componentProps.map(schemaProp => { return j.property( 'init', @@ -220,8 +189,6 @@ function buildViewConfig( .filter(event => event.bubblingType === 'bubble') .map(generateBubblingEventInfo); - bubblingEventNames.unshift(viewEvents); - const bubblingEvents = bubblingEventNames.length > 0 ? j.property( @@ -235,8 +202,6 @@ function buildViewConfig( .filter(event => event.bubblingType === 'direct') .map(generateDirectEventInfo); - directEventNames.unshift(viewDirectEvents); - const directEvents = directEventNames.length > 0 ? j.property( @@ -246,19 +211,12 @@ function buildViewConfig( ) : null; - const commands = j.property( - 'init', - j.identifier('Commands'), - j.objectExpression([]), - ); - const properties = [ j.property( 'init', j.identifier('uiViewClassName'), j.literal(componentName), ), - commands, bubblingEvents, directEvents, j.property('init', j.identifier('validAttributes'), validAttributes), @@ -273,13 +231,6 @@ module.exports = { const fileName = `${libraryName}NativeViewConfig.js`; const imports: Set = new Set(); - imports.add( - "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", - ); - imports.add( - "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", - ); - const moduleResults = Object.keys(schema.modules) .map(moduleName => { const components = schema.modules[moduleName].components; diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 729bfac1050bf9..1fd81850c2be64 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -14,24 +14,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ArrayPropsNativeComponentViewConfig = { uiViewClassName: 'ArrayPropsNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, names: true, disableds: true, progress: true, @@ -42,12 +30,7 @@ const ArrayPropsNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('ArrayPropsNativeComponent', ArrayPropsNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ArrayPropsNativeComponent', - () => ArrayPropsNativeComponentViewConfig, -); +registerGeneratedViewConfig('ArrayPropsNativeComponent', ArrayPropsNativeComponentViewConfig); module.exports = 'ArrayPropsNativeComponent'; ", @@ -68,34 +51,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const BooleanPropNativeComponentViewConfig = { uiViewClassName: 'BooleanPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('BooleanPropNativeComponent', BooleanPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'BooleanPropNativeComponent', - () => BooleanPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('BooleanPropNativeComponent', BooleanPropNativeComponentViewConfig); module.exports = 'BooleanPropNativeComponent'; ", @@ -116,34 +82,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ColorPropNativeComponentViewConfig = { uiViewClassName: 'ColorPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, tintColor: { process: require('processColor') }, }, }; -verifyComponentAttributeEquivalence('ColorPropNativeComponent', ColorPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ColorPropNativeComponent', - () => ColorPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('ColorPropNativeComponent', ColorPropNativeComponentViewConfig); module.exports = 'ColorPropNativeComponent'; ", @@ -164,34 +113,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const EnumPropsNativeComponentViewConfig = { uiViewClassName: 'EnumPropsNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, alignment: true, }, }; -verifyComponentAttributeEquivalence('EnumPropsNativeComponent', EnumPropsNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'EnumPropsNativeComponent', - () => EnumPropsNativeComponentViewConfig, -); +registerGeneratedViewConfig('EnumPropsNativeComponent', EnumPropsNativeComponentViewConfig); module.exports = 'EnumPropsNativeComponent'; ", @@ -212,17 +144,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const EventsNestedObjectNativeComponentViewConfig = { uiViewClassName: 'EventsNestedObjectNativeComponent', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topChange: { phasedRegistrationNames: { captured: 'onChangeCapture', @@ -231,23 +158,13 @@ const EventsNestedObjectNativeComponentViewConfig = { }, }, - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, onChange: true, }, }; -verifyComponentAttributeEquivalence('EventsNestedObjectNativeComponent', EventsNestedObjectNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'EventsNestedObjectNativeComponent', - () => EventsNestedObjectNativeComponentViewConfig, -); +registerGeneratedViewConfig('EventsNestedObjectNativeComponent', EventsNestedObjectNativeComponentViewConfig); module.exports = 'EventsNestedObjectNativeComponent'; ", @@ -268,17 +185,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const EventsNativeComponentViewConfig = { uiViewClassName: 'EventsNativeComponent', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topChange: { phasedRegistrationNames: { captured: 'onChangeCapture', @@ -295,15 +207,12 @@ const EventsNativeComponentViewConfig = { }, directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - topEventDirect: { registrationName: 'onEventDirect', }, }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, onChange: true, onEventDirect: true, @@ -311,12 +220,7 @@ const EventsNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('EventsNativeComponent', EventsNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'EventsNativeComponent', - () => EventsNativeComponentViewConfig, -); +registerGeneratedViewConfig('EventsNativeComponent', EventsNativeComponentViewConfig); module.exports = 'EventsNativeComponent'; ", @@ -337,24 +241,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const FloatPropNativeComponentViewConfig = { uiViewClassName: 'FloatPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, blurRadius: true, blurRadius2: true, blurRadius3: true, @@ -364,12 +256,7 @@ const FloatPropNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('FloatPropNativeComponent', FloatPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'FloatPropNativeComponent', - () => FloatPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('FloatPropNativeComponent', FloatPropNativeComponentViewConfig); module.exports = 'FloatPropNativeComponent'; ", @@ -390,34 +277,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ImagePropNativeComponentViewConfig = { uiViewClassName: 'ImagePropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, thumbImage: { process: require('resolveAssetSource') }, }, }; -verifyComponentAttributeEquivalence('ImagePropNativeComponent', ImagePropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ImagePropNativeComponent', - () => ImagePropNativeComponentViewConfig, -); +registerGeneratedViewConfig('ImagePropNativeComponent', ImagePropNativeComponentViewConfig); module.exports = 'ImagePropNativeComponent'; ", @@ -438,36 +308,19 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const IntegerPropNativeComponentViewConfig = { uiViewClassName: 'IntegerPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, progress1: true, progress2: true, progress3: true, }, }; -verifyComponentAttributeEquivalence('IntegerPropNativeComponent', IntegerPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'IntegerPropNativeComponent', - () => IntegerPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('IntegerPropNativeComponent', IntegerPropNativeComponentViewConfig); module.exports = 'IntegerPropNativeComponent'; ", @@ -488,17 +341,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const InterfaceOnlyComponentViewConfig = { uiViewClassName: 'RCTInterfaceOnlyComponent', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topChange: { phasedRegistrationNames: { captured: 'onChangeCapture', @@ -507,23 +355,13 @@ const InterfaceOnlyComponentViewConfig = { }, }, - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, accessibilityHint: true, onChange: true, }, }; -verifyComponentAttributeEquivalence('RCTInterfaceOnlyComponent', InterfaceOnlyComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'RCTInterfaceOnlyComponent', - () => InterfaceOnlyComponentViewConfig, -); +registerGeneratedViewConfig('RCTInterfaceOnlyComponent', InterfaceOnlyComponentViewConfig); module.exports = 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support ", @@ -544,24 +382,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ImageColorPropNativeComponentViewConfig = { uiViewClassName: 'ImageColorPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, thumbImage: { process: require('resolveAssetSource') }, color: { process: require('processColor') }, thumbTintColor: { process: require('processColor') }, @@ -569,12 +395,7 @@ const ImageColorPropNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('ImageColorPropNativeComponent', ImageColorPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ImageColorPropNativeComponent', - () => ImageColorPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('ImageColorPropNativeComponent', ImageColorPropNativeComponentViewConfig); module.exports = 'ImageColorPropNativeComponent'; ", @@ -595,34 +416,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const PointPropNativeComponentViewConfig = { uiViewClassName: 'PointPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, startPoint: { diff: require('pointsDiffer') }, }, }; -verifyComponentAttributeEquivalence('PointPropNativeComponent', PointPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'PointPropNativeComponent', - () => PointPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('PointPropNativeComponent', PointPropNativeComponentViewConfig); module.exports = 'PointPropNativeComponent'; ", @@ -643,34 +447,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const StringPropComponentViewConfig = { uiViewClassName: 'StringPropComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, accessibilityHint: true, }, }; -verifyComponentAttributeEquivalence('StringPropComponent', StringPropComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'StringPropComponent', - () => StringPropComponentViewConfig, -); +registerGeneratedViewConfig('StringPropComponent', StringPropComponentViewConfig); module.exports = 'StringPropComponent'; ", @@ -691,61 +478,29 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const MultiFile1NativeComponentViewConfig = { uiViewClassName: 'MultiFile1NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiFile1NativeComponent', MultiFile1NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiFile1NativeComponent', - () => MultiFile1NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiFile1NativeComponent', MultiFile1NativeComponentViewConfig); module.exports = 'MultiFile1NativeComponent'; const MultiFile2NativeComponentViewConfig = { uiViewClassName: 'MultiFile2NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiFile2NativeComponent', MultiFile2NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiFile2NativeComponent', - () => MultiFile2NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiFile2NativeComponent', MultiFile2NativeComponentViewConfig); module.exports = 'MultiFile2NativeComponent'; ", @@ -766,61 +521,29 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const MultiComponent1NativeComponentViewConfig = { uiViewClassName: 'MultiComponent1NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiComponent1NativeComponent', MultiComponent1NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiComponent1NativeComponent', - () => MultiComponent1NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiComponent1NativeComponent', MultiComponent1NativeComponentViewConfig); module.exports = 'MultiComponent1NativeComponent'; const MultiComponent2NativeComponentViewConfig = { uiViewClassName: 'MultiComponent2NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiComponent2NativeComponent', MultiComponent2NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiComponent2NativeComponent', - () => MultiComponent2NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiComponent2NativeComponent', MultiComponent2NativeComponentViewConfig); module.exports = 'MultiComponent2NativeComponent'; ", From efec97f2be535def834e0c2da061bb25875224c3 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:55 -0700 Subject: [PATCH 140/330] Add view config babel plugin Summary: This diff adds a babel plugin for the generated view configs which will inline them in the file instead of needing to check the view configs in (fb only) The way it works is: - babel reads the code - looks for type alias `CodegenNativeComponent` in `*NativeComponet.js` files - run the flow parser on the file source to create a schema - run the schema into codegen to get the view config source code - inject the generated source code back into the NativeComponent.js file - remove the original export - profit After this diff we will remove the `js1 build viewconfigs` command and the checked-in NativeViewConfig.js files Note: since this plugin is not published to open source, for now OSS will continue using the `requireNativeComponent` function Reviewed By: cpojer Differential Revision: D15516062 fbshipit-source-id: a8efb077773e04fd9753a7036682eeaae9175e09 --- .../PullToRefreshViewNativeComponent.js | 21 +++---- .../babel-plugin-inline-view-configs/BUCK | 23 ++++++++ .../__test_fixtures__/fixtures.js | 54 +++++++++++++++++ .../__snapshots__/index-test.js.snap | 52 ++++++++++++++++ .../__tests__/index-test.js | 32 ++++++++++ .../babel-plugin-inline-view-configs/index.js | 59 +++++++++++++++++++ .../package.json | 16 +++++ packages/react-native-codegen/BUCK | 23 ++++++++ packages/react-native-codegen/package.json | 2 +- .../src/cli/parser/parser.js | 5 +- .../cli/viewconfigs/generate-view-configs.js | 2 +- .../src/generators/RNCodegen.js | 14 +++++ .../src/parsers/flow/__tests__/parser-test.js | 2 +- .../src/parsers/flow/index.js | 16 +++-- 14 files changed, 298 insertions(+), 23 deletions(-) create mode 100644 packages/babel-plugin-inline-view-configs/BUCK create mode 100644 packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js create mode 100644 packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap create mode 100644 packages/babel-plugin-inline-view-configs/__tests__/index-test.js create mode 100644 packages/babel-plugin-inline-view-configs/index.js create mode 100644 packages/babel-plugin-inline-view-configs/package.json diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js index 5274896fb75e11..43105157841ded 100644 --- a/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js @@ -10,17 +10,13 @@ 'use strict'; -import type { - BubblingEvent, - WithDefault, - CodegenNativeComponent, -} from '../../Types/CodegenTypes'; - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - +import type {BubblingEvent, WithDefault} from '../../Types/CodegenTypes'; +import type {NativeComponent} from '../../Renderer/shims/ReactNative'; import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + type NativeProps = $ReadOnly<{| ...ViewProps, @@ -48,13 +44,10 @@ type NativeProps = $ReadOnly<{| refreshing: WithDefault, |}>; -type PullToRefreshViewType = CodegenNativeComponent< - 'PullToRefreshView', - NativeProps, ->; - -// TODO: Switch this over to require('./PullToRefreshNativeViewConfig') +// TODO: Switch this over to CodegenNativeComponent // once the native components are renamed in paper and fabric +type PullToRefreshViewType = Class>; + module.exports = ((requireNativeComponent( 'RCTRefreshControl', ): any): PullToRefreshViewType); diff --git a/packages/babel-plugin-inline-view-configs/BUCK b/packages/babel-plugin-inline-view-configs/BUCK new file mode 100644 index 00000000000000..8fd38289431bdb --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/BUCK @@ -0,0 +1,23 @@ +load("@fbsource//tools/build_defs/third_party:yarn_defs.bzl", "yarn_workspace") + +yarn_workspace( + name = "yarn-workspace", + srcs = glob( + ["**/*.js"], + exclude = [ + "**/__fixtures__/**", + "**/__flowtests__/**", + "**/__mocks__/**", + "**/__server_snapshot_tests__/**", + "**/__tests__/**", + "**/node_modules/**", + "**/node_modules/.bin/**", + "**/.*", + "**/.*/**", + "**/.*/.*", + "**/*.xcodeproj/**", + "**/*.xcworkspace/**", + ], + ), + visibility = ["PUBLIC"], +) diff --git a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js new file mode 100644 index 00000000000000..8af50cd1e1ffb8 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js @@ -0,0 +1,54 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; +const NOT_A_NATIVE_COMPONENT = ` +const requireNativeComponent = require('requireNativeComponent'); + +export default 'Not a view config' +`; + +const FULL_NATIVE_COMPONENT = ` +const requireNativeComponent = require('requireNativeComponent'); + +import type { + BubblingEvent, + DirectEvent, + WithDefault, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // Props + boolean_default_true_optional_both?: ?WithDefault, + + // Events + onDirectEventDefinedInlineNull: (event: DirectEvent) => void, + onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, +|}>; + +type Options = { + interfaceOnly: true, + isDeprecatedPaperComponentNameRCT: true, +}; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +module.exports = { + 'NotANativeComponent.js': NOT_A_NATIVE_COMPONENT, + 'FullNativeComponent.js': FULL_NATIVE_COMPONENT, +}; diff --git a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap new file mode 100644 index 00000000000000..7413b19d349409 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Babel plugin inline view configs can inline config for FullNativeComponent.js 1`] = ` +"const requireNativeComponent = require('requireNativeComponent'); + +import type { BubblingEvent, DirectEvent, WithDefault, CodegenNativeComponent } from 'CodegenFlowtypes'; +import type { ViewProps } from 'ViewPropTypes'; +type ModuleProps = $ReadOnly<{| ...ViewProps, + // Props + boolean_default_true_optional_both?: ?WithDefault, + // Events + onDirectEventDefinedInlineNull: (event: DirectEvent) => void, + onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, +|}>; +type Options = { + interfaceOnly: true, + isDeprecatedPaperComponentNameRCT: true, +}; +type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; + +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); + +const ModuleViewConfig = { + uiViewClassName: 'RCTModule', + bubblingEventTypes: { + topBubblingEventDefinedInlineNull: { + phasedRegistrationNames: { + captured: 'onBubblingEventDefinedInlineNullCapture', + bubbled: 'onBubblingEventDefinedInlineNull' + } + } + }, + directEventTypes: { + topDirectEventDefinedInlineNull: { + registrationName: 'onDirectEventDefinedInlineNull' + } + }, + validAttributes: { + boolean_default_true_optional_both: true, + onDirectEventDefinedInlineNull: true, + onBubblingEventDefinedInlineNull: true + } +}; +registerGeneratedViewConfig('RCTModule', ModuleViewConfig); +module.exports = 'RCTModule'; // RCT prefix present for paper support" +`; + +exports[`Babel plugin inline view configs can inline config for NotANativeComponent.js 1`] = ` +"const requireNativeComponent = require('requireNativeComponent'); + +export default 'Not a view config';" +`; diff --git a/packages/babel-plugin-inline-view-configs/__tests__/index-test.js b/packages/babel-plugin-inline-view-configs/__tests__/index-test.js new file mode 100644 index 00000000000000..da09f29a5df4d7 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/__tests__/index-test.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails oncall+react_native + * @format + */ + +'use strict'; + +const {transform: babelTransform} = require('@babel/core'); +const fixtures = require('../__test_fixtures__/fixtures.js'); + +function transform(filename) { + return babelTransform(fixtures[filename], { + plugins: [require('@babel/plugin-syntax-flow'), require('../index')], + babelrc: false, + filename, + }).code; +} + +describe('Babel plugin inline view configs', () => { + Object.keys(fixtures) + .sort() + .forEach(fixtureName => { + it(`can inline config for ${fixtureName}`, () => { + expect(transform(fixtureName)).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/babel-plugin-inline-view-configs/index.js b/packages/babel-plugin-inline-view-configs/index.js new file mode 100644 index 00000000000000..235e870912cf53 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/index.js @@ -0,0 +1,59 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ +'use strict'; + +const {parseString} = require('react-native-codegen/src/parsers/flow'); +const RNCodegen = require('react-native-codegen/src/generators/RNCodegen'); +const path = require('path'); + +function generateViewConfig(filename, code) { + const schema = parseString(code); + + const libraryName = path + .basename(filename) + .replace(/NativeComponent\.js$/, ''); + + return RNCodegen.generateViewConfig({ + schema, + libraryName, + }); +} + +module.exports = function(context) { + return { + pre(state) { + this.code = state.code; + this.filename = state.opts.filename; + this.inserted = false; + }, + visitor: { + TypeAlias(nodePath, state) { + if ( + !this.inserted && + nodePath.node.right && + nodePath.node.right.type === 'GenericTypeAnnotation' && + nodePath.node.right.id.name === 'CodegenNativeComponent' + ) { + const code = generateViewConfig(this.filename, this.code); + + // Remove the original export + nodePath.parentPath.traverse({ + MemberExpression(exportPath) { + if (exportPath.node.property.name === 'exports') { + exportPath.parentPath.remove(); + } + }, + }); + nodePath.insertAfter(context.parse(code).program.body); + this.inserted = true; + } + }, + }, + }; +}; diff --git a/packages/babel-plugin-inline-view-configs/package.json b/packages/babel-plugin-inline-view-configs/package.json new file mode 100644 index 00000000000000..1c7b21410cfa24 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/package.json @@ -0,0 +1,16 @@ +{ + "version": "0.0.0", + "name": "babel-plugin-inline-view-configs", + "description": "Babel plugin to inline view configs for React Native", + "repository": { + "type": "git", + "url": "git@github.com:facebook/react-native.git" + }, + "dependencies": { + "react-native-codegen": "*" + }, + "devDependencies": { + "@babel/core": "^7.0.0" + }, + "license": "MIT" +} diff --git a/packages/react-native-codegen/BUCK b/packages/react-native-codegen/BUCK index 8cd540b1244cdb..9fab520a5130b5 100644 --- a/packages/react-native-codegen/BUCK +++ b/packages/react-native-codegen/BUCK @@ -2,6 +2,7 @@ load("@fbsource//tools/build_defs:default_platform_defs.bzl", "ANDROID", "APPLE" load("@fbsource//tools/build_defs:fb_native_wrapper.bzl", "fb_native") load("@fbsource//tools/build_defs:fb_xplat_cxx_binary.bzl", "fb_xplat_cxx_binary") load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "rn_xplat_cxx_library") +load("@fbsource//tools/build_defs/third_party:yarn_defs.bzl", "yarn_workspace") load("@fbsource//xplat/js/react-native-github/packages/react-native-codegen:DEFS.bzl", "rn_codegen_test") fb_native.sh_binary( @@ -173,3 +174,25 @@ rn_xplat_cxx_library( ":generated_components-TWO_COMPONENTS_SAME_FILE", ], ) + +yarn_workspace( + name = "yarn-workspace", + srcs = glob( + ["**/*.js"], + exclude = [ + "**/__fixtures__/**", + "**/__flowtests__/**", + "**/__mocks__/**", + "**/__server_snapshot_tests__/**", + "**/__tests__/**", + "**/node_modules/**", + "**/node_modules/.bin/**", + "**/.*", + "**/.*/**", + "**/.*/.*", + "**/*.xcodeproj/**", + "**/*.xcworkspace/**", + ], + ), + visibility = ["PUBLIC"], +) diff --git a/packages/react-native-codegen/package.json b/packages/react-native-codegen/package.json index 7fffd48187652e..85a9de6d5acfaf 100644 --- a/packages/react-native-codegen/package.json +++ b/packages/react-native-codegen/package.json @@ -1,6 +1,6 @@ { "version": "0.0.1", - "name": "react-native-codgen", + "name": "react-native-codegen", "description": "⚛️ Code generation tools for React Native", "repository": { "type": "git", diff --git a/packages/react-native-codegen/src/cli/parser/parser.js b/packages/react-native-codegen/src/cli/parser/parser.js index c1ec866f8a8ba1..1cc5247033ba23 100644 --- a/packages/react-native-codegen/src/cli/parser/parser.js +++ b/packages/react-native-codegen/src/cli/parser/parser.js @@ -14,7 +14,10 @@ const FlowParser = require('../../parsers/flow'); function parseFiles(files: Array) { files.forEach(filename => { - console.log(filename, JSON.stringify(FlowParser.parse(filename), null, 2)); + console.log( + filename, + JSON.stringify(FlowParser.parseFile(filename), null, 2), + ); }); } diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js index 64abcb27935b87..9730f9722ed897 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js @@ -33,7 +33,7 @@ function generateFilesWithResults( return files.reduce((aggregated, filename) => { const schema = config.parser === 'flow' - ? FlowParser.parse(filename) + ? FlowParser.parseFile(filename) : SchemaParser.parse(filename); if (schema && schema.modules) { const libraryName = path diff --git a/packages/react-native-codegen/src/generators/RNCodegen.js b/packages/react-native-codegen/src/generators/RNCodegen.js index ac9383f4f2ff6d..1a83cc27f901e8 100644 --- a/packages/react-native-codegen/src/generators/RNCodegen.js +++ b/packages/react-native-codegen/src/generators/RNCodegen.js @@ -118,4 +118,18 @@ module.exports = { return writeMapToFiles(filesToUpdate, outputDirectory); }, + generateViewConfig({libraryName, schema}: Options): string { + schemaValidator.validate(schema); + + const result = generateViewConfigJs + .generate(libraryName, schema) + .values() + .next(); + + if (typeof result.value !== 'string') { + throw new Error(`Failed to generate view config for ${libraryName}`); + } + + return result.value; + }, }; diff --git a/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js b/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js index 05c7374569a424..3807a1670ba569 100644 --- a/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js +++ b/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js @@ -22,7 +22,7 @@ describe('RN Codegen Flow Parser', () => { .sort() .forEach(fixtureName => { it(`can generate fixture ${fixtureName}`, () => { - expect(FlowParser.parse(fixtureName)).toMatchSnapshot(); + expect(FlowParser.parseFile(fixtureName)).toMatchSnapshot(); }); }); }); diff --git a/packages/react-native-codegen/src/parsers/flow/index.js b/packages/react-native-codegen/src/parsers/flow/index.js index 861b444412e86b..019560fcf97a5f 100644 --- a/packages/react-native-codegen/src/parsers/flow/index.js +++ b/packages/react-native-codegen/src/parsers/flow/index.js @@ -71,8 +71,7 @@ function getPropProperties(propsTypeName, types) { } } -function parseFileAst(filename: string) { - const contents = fs.readFileSync(filename, 'utf8'); +function processString(contents: string) { const ast = flowParser.parse(contents); const types = getTypes(ast); @@ -96,10 +95,17 @@ function parseFileAst(filename: string) { }; } -function parse(filename: string): ?SchemaType { - return buildSchema(parseFileAst(filename)); +function parseFile(filename: string): ?SchemaType { + const contents = fs.readFileSync(filename, 'utf8'); + + return buildSchema(processString(contents)); +} + +function parseString(contents: string): ?SchemaType { + return buildSchema(processString(contents)); } module.exports = { - parse, + parseFile, + parseString, }; From 504fc0c7d08a0c8e80fb5198c72bba6c0be13de8 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:56 -0700 Subject: [PATCH 141/330] Update flow parser to use codegenNativeComponent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This diff updated the codegen flow types syntax replacing: ``` type Options = { isDeprecatedPaperComponentNameRCT: true, }; type ActivityIndicatorNativeType = CodegenNativeComponent< 'ActivityIndicatorView', NativeProps, Options, >; module.exports = ((requireNativeComponent( 'RCTActivityIndicatorView', ): any): ActivityIndicatorNativeType); ``` with: ``` export default codegenNativeComponent('ActivityIndicatorView', { isDeprecatedPaperComponentNameRCT: true, }); ``` This is from Tim's comment in the [View Config Codegen Quip](https://fb.quip.com/jR2aASHad4Se): > What it CodegenNativeComponent were instead `NativeComponent.fromFlow('…')` that returned `'...'`? >And the Babel plugin swapped it for NativeComponent.fromSchema('...', {…}) which would both register and return '...'? I went with `codegenNativeComponent` because it has nice parity with `requireNativeComponent` I also didn't update the babel output here (we can update that whenever) because I think `registerGeneratedViewConfig` is more clear for what it's doing Reviewed By: cpojer Differential Revision: D15602077 fbshipit-source-id: 2d24dc32136ba6d31724f8c929b51417ba625a58 --- .../ActivityIndicator/ActivityIndicator.js | 2 +- .../ActivityIndicatorViewNativeComponent.js | 21 ++---- .../Slider/SliderNativeComponent.js | 13 ++-- Libraries/Types/CodegenTypes.js | 9 +-- Libraries/Utilities/codegenNativeComponent.js | 41 ++++++++++++ .../__test_fixtures__/fixtures.js | 11 +-- .../__snapshots__/index-test.js.snap | 11 +-- .../babel-plugin-inline-view-configs/index.js | 46 +++++++------ .../src/generators/GenerateViewConfigJs.js | 2 +- .../GenerateViewConfigJs-test.js.snap | 34 +++++----- .../flow/__test_fixtures__/fixtures.js | 67 +++++++------------ .../src/parsers/flow/index.js | 27 +++++--- .../src/parsers/flow/options.js | 6 +- 13 files changed, 143 insertions(+), 147 deletions(-) create mode 100644 Libraries/Utilities/codegenNativeComponent.js diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index 70f73db0ce0cdd..df6cd3c5cc1b90 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -21,7 +21,7 @@ import type {ViewProps} from '../View/ViewPropTypes'; const PlatformActivityIndicator = Platform.OS === 'android' ? require('../ProgressBarAndroid/ProgressBarAndroid') - : require('./ActivityIndicatorViewNativeComponent'); + : require('./ActivityIndicatorViewNativeComponent').default; const GRAY = '#999999'; diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js index 213f1d0e796a24..8781a230d4d437 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js @@ -10,15 +10,12 @@ 'use strict'; -import type { - WithDefault, - CodegenNativeComponent, -} from '../../Types/CodegenTypes'; +import type {WithDefault} from '../../Types/CodegenTypes'; import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; type NativeProps = $ReadOnly<{| ...ViewProps, @@ -53,16 +50,6 @@ type NativeProps = $ReadOnly<{| size?: ?WithDefault<'small' | 'large', 'small'>, |}>; -type Options = { +export default codegenNativeComponent('ActivityIndicatorView', { isDeprecatedPaperComponentNameRCT: true, -}; - -type ActivityIndicatorNativeType = CodegenNativeComponent< - 'ActivityIndicatorView', - NativeProps, - Options, ->; - -module.exports = ((requireNativeComponent( - 'RCTActivityIndicatorView', -): any): ActivityIndicatorNativeType); +}); diff --git a/Libraries/Components/Slider/SliderNativeComponent.js b/Libraries/Components/Slider/SliderNativeComponent.js index d7d90e0cdab608..004fed84ed8ad5 100644 --- a/Libraries/Components/Slider/SliderNativeComponent.js +++ b/Libraries/Components/Slider/SliderNativeComponent.js @@ -15,15 +15,14 @@ import type { BubblingEvent, DirectEvent, WithDefault, - CodegenNativeComponent, } from '../../Types/CodegenTypes'; +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; + import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ImageSource} from '../../Image/ImageSource'; import type {ViewProps} from '../View/ViewPropTypes'; -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - type Event = $ReadOnly<{| value: Float, fromUser?: boolean, @@ -54,11 +53,7 @@ type NativeProps = $ReadOnly<{| onSlidingComplete?: ?(event: DirectEvent) => void, |}>; -type Options = { +module.exports = codegenNativeComponent('Slider', { interfaceOnly: true, isDeprecatedPaperComponentNameRCT: true, -}; - -type SliderType = CodegenNativeComponent<'Slider', NativeProps, Options>; - -module.exports = ((requireNativeComponent('RCTSlider'): any): SliderType); +}); diff --git a/Libraries/Types/CodegenTypes.js b/Libraries/Types/CodegenTypes.js index 4ee7fadd651019..b3e6c853e025cd 100644 --- a/Libraries/Types/CodegenTypes.js +++ b/Libraries/Types/CodegenTypes.js @@ -26,13 +26,6 @@ export type Int32 = number; // // TODO: (rickhanlonii) T44881457 If a default is provided, it should always be optional // but that is currently not supported in the codegen since we require a default -// eslint-disable-next-line no-unused-vars -export type WithDefault = Type; - -// We're not using ComponentName or Options in JS -// We only use these types to codegen native code // // eslint-disable-next-line no-unused-vars -export type CodegenNativeComponent = Class< - NativeComponent, ->; +export type WithDefault = Type; diff --git a/Libraries/Utilities/codegenNativeComponent.js b/Libraries/Utilities/codegenNativeComponent.js new file mode 100644 index 00000000000000..ad55cc84354793 --- /dev/null +++ b/Libraries/Utilities/codegenNativeComponent.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ +// TODO: move this file to shims/ReactNative (requires React update and sync) + +'use strict'; + +import type {NativeComponent} from '../../Libraries/Renderer/shims/ReactNative'; +import requireNativeComponent from '../../Libraries/ReactNative/requireNativeComponent'; + +// TODO: import from CodegenSchema once workspaces are enabled +type Options = $ReadOnly<{| + interfaceOnly?: boolean, + isDeprecatedPaperComponentNameRCT?: boolean, +|}>; + +function codegenNativeComponent( + componentName: string, + options?: Options, +): Class> { + let componentNameInUse = componentName; + if (options && options.isDeprecatedPaperComponentNameRCT === true) { + componentNameInUse = `RCT${componentName}`; + } + + // If this function is run at runtime then that means the view configs were not + // generated with the view config babel plugin, so we need to require the native component. + // + // This will be useful during migration, but eventually this will error. + return ((requireNativeComponent(componentNameInUse): any): Class< + NativeComponent, + >); +} + +export default codegenNativeComponent; diff --git a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js index 8af50cd1e1ffb8..1a26fc15aef783 100644 --- a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js +++ b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js @@ -16,13 +16,12 @@ export default 'Not a view config' `; const FULL_NATIVE_COMPONENT = ` -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, WithDefault, - CodegenNativeComponent, } from 'CodegenFlowtypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -38,14 +37,10 @@ type ModuleProps = $ReadOnly<{| onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, |}>; -type Options = { +export default codegenNativeComponent('Module', { interfaceOnly: true, isDeprecatedPaperComponentNameRCT: true, -}; - -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +}); `; module.exports = { diff --git a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap index 7413b19d349409..898ad51671f144 100644 --- a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap +++ b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Babel plugin inline view configs can inline config for FullNativeComponent.js 1`] = ` -"const requireNativeComponent = require('requireNativeComponent'); +"const codegenNativeComponent = require('codegenNativeComponent'); -import type { BubblingEvent, DirectEvent, WithDefault, CodegenNativeComponent } from 'CodegenFlowtypes'; +import type { BubblingEvent, DirectEvent, WithDefault } from 'CodegenFlowtypes'; import type { ViewProps } from 'ViewPropTypes'; type ModuleProps = $ReadOnly<{| ...ViewProps, // Props @@ -12,11 +12,6 @@ type ModuleProps = $ReadOnly<{| ...ViewProps, onDirectEventDefinedInlineNull: (event: DirectEvent) => void, onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, |}>; -type Options = { - interfaceOnly: true, - isDeprecatedPaperComponentNameRCT: true, -}; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); @@ -42,7 +37,7 @@ const ModuleViewConfig = { } }; registerGeneratedViewConfig('RCTModule', ModuleViewConfig); -module.exports = 'RCTModule'; // RCT prefix present for paper support" +export default 'RCTModule'; // RCT prefix present for paper support" `; exports[`Babel plugin inline view configs can inline config for NotANativeComponent.js 1`] = ` diff --git a/packages/babel-plugin-inline-view-configs/index.js b/packages/babel-plugin-inline-view-configs/index.js index 235e870912cf53..c7ea03798d958c 100644 --- a/packages/babel-plugin-inline-view-configs/index.js +++ b/packages/babel-plugin-inline-view-configs/index.js @@ -25,33 +25,39 @@ function generateViewConfig(filename, code) { }); } +function isCodegenDeclaration(declaration) { + if (!declaration) { + return false; + } + + if ( + declaration.left && + declaration.left.left && + declaration.left.left.name === 'codegenNativeComponent' + ) { + return true; + } else if ( + declaration.callee && + declaration.callee.name && + declaration.callee.name === 'codegenNativeComponent' + ) { + return true; + } + + return false; +} + module.exports = function(context) { return { pre(state) { this.code = state.code; this.filename = state.opts.filename; - this.inserted = false; }, visitor: { - TypeAlias(nodePath, state) { - if ( - !this.inserted && - nodePath.node.right && - nodePath.node.right.type === 'GenericTypeAnnotation' && - nodePath.node.right.id.name === 'CodegenNativeComponent' - ) { - const code = generateViewConfig(this.filename, this.code); - - // Remove the original export - nodePath.parentPath.traverse({ - MemberExpression(exportPath) { - if (exportPath.node.property.name === 'exports') { - exportPath.parentPath.remove(); - } - }, - }); - nodePath.insertAfter(context.parse(code).program.body); - this.inserted = true; + ExportDefaultDeclaration(nodePath, state) { + if (isCodegenDeclaration(nodePath.node.declaration)) { + const viewConfig = generateViewConfig(this.filename, this.code); + nodePath.replaceWithMultiple(context.parse(viewConfig).program.body); } }, }, diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index d5f8cde857f88a..ef5ec793b09b21 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -89,7 +89,7 @@ const ::_COMPONENT_NAME_::ViewConfig = VIEW_CONFIG; registerGeneratedViewConfig('::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', ::_COMPONENT_NAME_::ViewConfig); -module.exports = '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_:: +export default '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_:: `.trim(); // Replicates the behavior of RCTNormalizeInputEventName in RCTEventDispatcher.m diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 1fd81850c2be64..16d056333dfcab 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -32,7 +32,7 @@ const ArrayPropsNativeComponentViewConfig = { registerGeneratedViewConfig('ArrayPropsNativeComponent', ArrayPropsNativeComponentViewConfig); -module.exports = 'ArrayPropsNativeComponent'; +export default 'ArrayPropsNativeComponent'; ", } `; @@ -63,7 +63,7 @@ const BooleanPropNativeComponentViewConfig = { registerGeneratedViewConfig('BooleanPropNativeComponent', BooleanPropNativeComponentViewConfig); -module.exports = 'BooleanPropNativeComponent'; +export default 'BooleanPropNativeComponent'; ", } `; @@ -94,7 +94,7 @@ const ColorPropNativeComponentViewConfig = { registerGeneratedViewConfig('ColorPropNativeComponent', ColorPropNativeComponentViewConfig); -module.exports = 'ColorPropNativeComponent'; +export default 'ColorPropNativeComponent'; ", } `; @@ -125,7 +125,7 @@ const EnumPropsNativeComponentViewConfig = { registerGeneratedViewConfig('EnumPropsNativeComponent', EnumPropsNativeComponentViewConfig); -module.exports = 'EnumPropsNativeComponent'; +export default 'EnumPropsNativeComponent'; ", } `; @@ -166,7 +166,7 @@ const EventsNestedObjectNativeComponentViewConfig = { registerGeneratedViewConfig('EventsNestedObjectNativeComponent', EventsNestedObjectNativeComponentViewConfig); -module.exports = 'EventsNestedObjectNativeComponent'; +export default 'EventsNestedObjectNativeComponent'; ", } `; @@ -222,7 +222,7 @@ const EventsNativeComponentViewConfig = { registerGeneratedViewConfig('EventsNativeComponent', EventsNativeComponentViewConfig); -module.exports = 'EventsNativeComponent'; +export default 'EventsNativeComponent'; ", } `; @@ -258,7 +258,7 @@ const FloatPropNativeComponentViewConfig = { registerGeneratedViewConfig('FloatPropNativeComponent', FloatPropNativeComponentViewConfig); -module.exports = 'FloatPropNativeComponent'; +export default 'FloatPropNativeComponent'; ", } `; @@ -289,7 +289,7 @@ const ImagePropNativeComponentViewConfig = { registerGeneratedViewConfig('ImagePropNativeComponent', ImagePropNativeComponentViewConfig); -module.exports = 'ImagePropNativeComponent'; +export default 'ImagePropNativeComponent'; ", } `; @@ -322,7 +322,7 @@ const IntegerPropNativeComponentViewConfig = { registerGeneratedViewConfig('IntegerPropNativeComponent', IntegerPropNativeComponentViewConfig); -module.exports = 'IntegerPropNativeComponent'; +export default 'IntegerPropNativeComponent'; ", } `; @@ -363,7 +363,7 @@ const InterfaceOnlyComponentViewConfig = { registerGeneratedViewConfig('RCTInterfaceOnlyComponent', InterfaceOnlyComponentViewConfig); -module.exports = 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support +export default 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support ", } `; @@ -397,7 +397,7 @@ const ImageColorPropNativeComponentViewConfig = { registerGeneratedViewConfig('ImageColorPropNativeComponent', ImageColorPropNativeComponentViewConfig); -module.exports = 'ImageColorPropNativeComponent'; +export default 'ImageColorPropNativeComponent'; ", } `; @@ -428,7 +428,7 @@ const PointPropNativeComponentViewConfig = { registerGeneratedViewConfig('PointPropNativeComponent', PointPropNativeComponentViewConfig); -module.exports = 'PointPropNativeComponent'; +export default 'PointPropNativeComponent'; ", } `; @@ -459,7 +459,7 @@ const StringPropComponentViewConfig = { registerGeneratedViewConfig('StringPropComponent', StringPropComponentViewConfig); -module.exports = 'StringPropComponent'; +export default 'StringPropComponent'; ", } `; @@ -490,7 +490,7 @@ const MultiFile1NativeComponentViewConfig = { registerGeneratedViewConfig('MultiFile1NativeComponent', MultiFile1NativeComponentViewConfig); -module.exports = 'MultiFile1NativeComponent'; +export default 'MultiFile1NativeComponent'; const MultiFile2NativeComponentViewConfig = { uiViewClassName: 'MultiFile2NativeComponent', @@ -502,7 +502,7 @@ const MultiFile2NativeComponentViewConfig = { registerGeneratedViewConfig('MultiFile2NativeComponent', MultiFile2NativeComponentViewConfig); -module.exports = 'MultiFile2NativeComponent'; +export default 'MultiFile2NativeComponent'; ", } `; @@ -533,7 +533,7 @@ const MultiComponent1NativeComponentViewConfig = { registerGeneratedViewConfig('MultiComponent1NativeComponent', MultiComponent1NativeComponentViewConfig); -module.exports = 'MultiComponent1NativeComponent'; +export default 'MultiComponent1NativeComponent'; const MultiComponent2NativeComponentViewConfig = { uiViewClassName: 'MultiComponent2NativeComponent', @@ -545,7 +545,7 @@ const MultiComponent2NativeComponentViewConfig = { registerGeneratedViewConfig('MultiComponent2NativeComponent', MultiComponent2NativeComponentViewConfig); -module.exports = 'MultiComponent2NativeComponent'; +export default 'MultiComponent2NativeComponent'; ", } `; diff --git a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js index d971d6dba4e5dc..a54aa2bb62bebc 100644 --- a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js @@ -55,6 +55,7 @@ const EVENT_DEFINITION = ` } } `; + const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` /** * Copyright (c) Facebook, Inc. and its affiliates. @@ -68,14 +69,13 @@ const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, WithDefault, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -90,14 +90,10 @@ type ModuleProps = $ReadOnly<{| onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, |}>; -type Options = { +export default codegenNativeComponent('Module', { interfaceOnly: true, isDeprecatedPaperComponentNameRCT: true, -}; - -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +}); `; const ALL_PROP_TYPES_NO_EVENTS = ` @@ -113,14 +109,13 @@ const ALL_PROP_TYPES_NO_EVENTS = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Int32, Float, WithDefault, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ColorValue, ColorArrayValue, PointValue} from 'StyleSheetTypes'; import type {ImageSource} from 'ImageSource'; @@ -184,9 +179,7 @@ type ModuleProps = $ReadOnly<{| point_optional_both?: ?PointValue, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const ARRAY_PROP_TYPES_NO_EVENTS = ` @@ -202,14 +195,13 @@ const ARRAY_PROP_TYPES_NO_EVENTS = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Int32, Float, WithDefault, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ColorValue, PointValue} from 'StyleSheetTypes'; import type {ImageSource} from 'ImageSource'; @@ -268,9 +260,7 @@ type ModuleProps = $ReadOnly<{| array_point_optional_both?: ?$ReadOnlyArray, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = ` @@ -286,15 +276,14 @@ const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Int32, Float, BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -368,9 +357,7 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES = ` @@ -386,15 +373,14 @@ const EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Float, Int32, BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -430,9 +416,7 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_AS_NULL_IN_FILE = ` @@ -448,13 +432,12 @@ const EVENTS_DEFINED_AS_NULL_IN_FILE = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -492,9 +475,8 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_AS_NULL_INLINE = ` @@ -510,13 +492,12 @@ const EVENTS_DEFINED_AS_NULL_INLINE = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypese'; import type {ViewProps} from 'ViewPropTypes'; @@ -549,9 +530,7 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; module.exports = { diff --git a/packages/react-native-codegen/src/parsers/flow/index.js b/packages/react-native-codegen/src/parsers/flow/index.js index 019560fcf97a5f..bf1129bcb157fb 100644 --- a/packages/react-native-codegen/src/parsers/flow/index.js +++ b/packages/react-native-codegen/src/parsers/flow/index.js @@ -20,19 +20,24 @@ const {getProps} = require('./props'); const {getOptions} = require('./options'); const {getExtendsProps} = require('./extends'); -function findConfig(types) { +function findConfig(ast) { const foundConfigs = []; - Object.keys(types).forEach(key => { + const allExports = ast.body.filter( + node => node.type === 'ExportDefaultDeclaration', + ); + + allExports.forEach(statement => { try { - const type = types[key]; - if (type.right.id.name === 'CodegenNativeComponent') { - const params = type.right.typeParameters.params; + if (statement.declaration.callee.name === 'codegenNativeComponent') { + const typeArgumentParams = statement.declaration.typeArguments.params; + const funcArgumentParams = statement.declaration.arguments; + const nativeComponentType = {}; - nativeComponentType.componentName = params[0].value; - nativeComponentType.propsTypeName = params[1].id.name; - if (params.length > 2) { - nativeComponentType.optionsTypeName = params[2].id.name; + nativeComponentType.propsTypeName = typeArgumentParams[0].id.name; + nativeComponentType.componentName = funcArgumentParams[0].value; + if (funcArgumentParams.length > 1) { + nativeComponentType.optionsExpression = funcArgumentParams[1]; } foundConfigs.push(nativeComponentType); } @@ -75,12 +80,12 @@ function processString(contents: string) { const ast = flowParser.parse(contents); const types = getTypes(ast); - const {componentName, propsTypeName, optionsTypeName} = findConfig(types); + const {componentName, propsTypeName, optionsExpression} = findConfig(ast); const propProperties = getPropProperties(propsTypeName, types); const extendsProps = getExtendsProps(propProperties); - const options = getOptions(types[optionsTypeName]); + const options = getOptions(optionsExpression); const props = getProps(propProperties); const events = getEvents(propProperties, types); diff --git a/packages/react-native-codegen/src/parsers/flow/options.js b/packages/react-native-codegen/src/parsers/flow/options.js index 157de570179f37..1b42e25fa3851a 100644 --- a/packages/react-native-codegen/src/parsers/flow/options.js +++ b/packages/react-native-codegen/src/parsers/flow/options.js @@ -15,12 +15,12 @@ import type {OptionsShape} from '../../CodegenSchema.js'; // $FlowFixMe there's no flowtype for ASTs type OptionsAST = Object; -function getOptions(optionsDefinition: OptionsAST): ?OptionsShape { - if (!optionsDefinition) { +function getOptions(optionsExpression: OptionsAST): ?OptionsShape { + if (!optionsExpression) { return null; } try { - return optionsDefinition.right.properties.reduce((options, prop) => { + return optionsExpression.properties.reduce((options, prop) => { options[prop.key.name] = prop.value.value; return options; }, {}); From 97d439e0baee3cba2b2e0841bbb8f8db88965fb1 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:56 -0700 Subject: [PATCH 142/330] Remove checked-in view configs and js1 build viewconfigs Summary: Now that we have the babel plugin, we can remove the checked in view configs Note that this requires switching the old NativeComponent.js files back to `requireNativeComponent` for open source support (until the babel plugin and codegen are published to a package) The babel plugin replaces this export with the inline view config Reviewed By: cpojer Differential Revision: D15524779 fbshipit-source-id: ab819ce6f24cb2f15a1897ed6d510a0db6aff3a1 --- .../viewconfigs/generate-view-configs-cli.js | 38 --------- .../cli/viewconfigs/generate-view-configs.js | 81 ------------------- .../cli/viewconfigs/generate-view-configs.sh | 15 ---- 3 files changed, 134 deletions(-) delete mode 100644 packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js delete mode 100644 packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js delete mode 100755 packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js deleted file mode 100644 index 2ce923a97a16ac..00000000000000 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -const generate = require('./generate-view-configs'); -const yargs = require('yargs'); - -const yargv = yargs.strict().option('t', { - alias: 'test', - describe: 'Test the changes and do not write files', - requiresArg: false, - type: 'boolean', -}); - -const argv = yargv.argv; -const fileList = argv._[0].split('\n'); - -const CURRENT_VIEW_CONFIG_FILES = []; - -generate( - fileList.filter(fileName => - CURRENT_VIEW_CONFIG_FILES.find(supportedFileName => - fileName.endsWith(supportedFileName), - ), - ), - /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.99 was deployed. To see the error, delete this - * comment and run Flow. */ - {test: argv.test, parser: 'flow'}, -); diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js deleted file mode 100644 index 9730f9722ed897..00000000000000 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -const RNCodegen = require('../../generators/RNCodegen.js'); -const SchemaParser = require('../../parsers/schema'); -const FlowParser = require('../../parsers/flow'); - -const path = require('path'); - -type Result = $ReadOnly<{| - libraryName: string, - success: boolean, -|}>; - -type Config = $ReadOnly<{| - test?: boolean, - parser?: 'schema' | 'flow', -|}>; - -function generateFilesWithResults( - files: Array, - config: Config, -): Array { - return files.reduce((aggregated, filename) => { - const schema = - config.parser === 'flow' - ? FlowParser.parseFile(filename) - : SchemaParser.parse(filename); - if (schema && schema.modules) { - const libraryName = path - .basename(filename) - .replace(/NativeComponent\.js$/, ''); - const success = RNCodegen.generate( - { - schema, - libraryName, - outputDirectory: path.dirname(filename), - }, - {generators: ['view-configs'], test: config.test}, - ); - - aggregated.push({ - libraryName, - success, - }); - } - return aggregated; - }, []); -} - -function generate(files: Array, config: Config): void { - console.log(`${config.test ? 'Testing' : 'Generating'} view configs`); - - const results = generateFilesWithResults(files, config); - - const failed = results.filter(result => !result.success); - const totalCount = results.length; - - console.log( - `\n${config.test ? 'Tested' : 'Generated'} ${totalCount} view configs`, - ); - - if (failed.length) { - if (config.test === true) { - console.error(`${failed.length} configs changed`); - console.error("Please re-run 'js1 build viewconfigs'"); - } - process.exit(1); - } -} - -module.exports = generate; diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh deleted file mode 100755 index 355c9fe560b83a..00000000000000 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# set -euo pipefail - -set -e -set -u - -THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) - -FILES=$(find "$JS_DIR/" -name "*NativeComponent.js" -print -type f) - -# shellcheck source=xplat/js/env-utils/setup_env_vars.sh -source "$THIS_DIR/../../../../../../env-utils/setup_env_vars.sh" - -exec "$FLOW_NODE_BINARY" "$THIS_DIR/generate-view-configs-cli.js" "$@" "$FILES" From e5a8e3a53e8106b861624ece5e7a70e662548467 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 7 Jun 2019 13:08:28 -0700 Subject: [PATCH 143/330] Initialize TurboModules after creation Summary: When `ModuleHolder` instantiates `NativeModules`, it calls the `initialize()` method. We should replicate this call in the TurboModule system. `NativeModule.initialize()` is meant to be called after ReactApplicationContext is initialized. TurboModuleManager is initialized after ReactApplicationContext is initialized. Therefore, after we create the TurboModule, it should be safe to call `initialize()` on it. Reviewed By: mdvacca Differential Revision: D15711540 fbshipit-source-id: c2ef1a2ab164996bfc5716d81b3b3c716bf0e120 --- .../react/turbomodule/core/TurboModuleManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java index 511dd690f31a03..c887c777bc050f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java @@ -12,6 +12,7 @@ import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JSIModule; import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.queue.MessageQueueThread; import com.facebook.react.turbomodule.core.interfaces.JSCallInvokerHolder; @@ -53,6 +54,12 @@ protected TurboModule getJavaModule(String name) { final TurboModule turboModule = mTurbomoduleManagerDelegate.getModule(name); if (turboModule != null) { + /** + * TurboModuleManager is initialized after ReactApplicationContext has been setup. + * Therefore, it's safe to call initialize on the TurboModule. + */ + ((NativeModule)turboModule).initialize(); + mTurboModules.put(name, turboModule); } } From 3312146ced29c36c762954d957b5b9c715d625d8 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 7 Jun 2019 13:08:28 -0700 Subject: [PATCH 144/330] Make NativeModule names public Summary: To implement the `getModule` method of `TurboReactPackages`, we need to be able to access the JS Names of NativeModule classes. Reviewed By: fkgozali Differential Revision: D15711544 fbshipit-source-id: 51a649d08410557a4bdbf20d065bf98646a8d18a --- .../com/facebook/react/modules/appstate/AppStateModule.java | 2 +- .../java/com/facebook/react/modules/blob/BlobModule.java | 2 +- .../com/facebook/react/modules/blob/FileReaderModule.java | 2 +- .../facebook/react/modules/camera/ImageEditingManager.java | 2 +- .../com/facebook/react/modules/camera/ImageStoreManager.java | 5 +++-- .../com/facebook/react/modules/network/NetworkingModule.java | 2 +- .../java/com/facebook/react/modules/share/ShareModule.java | 5 +++-- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java index 6dc073cd275d54..4b43bb7c0cf39a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java @@ -26,7 +26,7 @@ public class AppStateModule extends ReactContextBaseJavaModule implements LifecycleEventListener, WindowFocusChangeListener { - protected static final String NAME = "AppState"; + public static final String NAME = "AppState"; public static final String APP_STATE_ACTIVE = "active"; public static final String APP_STATE_BACKGROUND = "background"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 830180c6ffc308..d968e5800c7813 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -48,7 +48,7 @@ @ReactModule(name = BlobModule.NAME) public class BlobModule extends ReactContextBaseJavaModule { - protected static final String NAME = "BlobModule"; + public static final String NAME = "BlobModule"; private final Map mBlobs = new HashMap<>(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java index a5293261ad9876..bb8f35e8d37208 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java @@ -20,7 +20,7 @@ @ReactModule(name = FileReaderModule.NAME) public class FileReaderModule extends ReactContextBaseJavaModule { - protected static final String NAME = "FileReaderModule"; + public static final String NAME = "FileReaderModule"; private static final String ERROR_INVALID_BLOB = "ERROR_INVALID_BLOB"; public FileReaderModule(ReactApplicationContext reactContext) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java index 417b7a002a59ae..152afdfd340f2c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java @@ -55,7 +55,7 @@ @ReactModule(name = ImageEditingManager.NAME) public class ImageEditingManager extends ReactContextBaseJavaModule { - protected static final String NAME = "ImageEditingManager"; + public static final String NAME = "ImageEditingManager"; private static final List LOCAL_URI_PREFIXES = Arrays.asList( "file://", "content://"); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java index 235cdd1931bb7a..afe625ffc56fc5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java @@ -27,9 +27,10 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; -@ReactModule(name = "ImageStoreManager") +@ReactModule(name = ImageStoreManager.NAME) public class ImageStoreManager extends ReactContextBaseJavaModule { + public static final String NAME = "ImageStoreManager"; private static final int BUFFER_SIZE = 8192; public ImageStoreManager(ReactApplicationContext reactContext) { @@ -38,7 +39,7 @@ public ImageStoreManager(ReactApplicationContext reactContext) { @Override public String getName() { - return "ImageStoreManager"; + return NAME; } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 888fcc25f03c46..9c90084b9292b5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -103,7 +103,7 @@ public interface ResponseHandler { WritableMap toResponseData(ResponseBody body) throws IOException; } - protected static final String NAME = "Networking"; + public static final String NAME = "Networking"; private static final String TAG = "NetworkingModule"; private static final String CONTENT_ENCODING_HEADER_NAME = "content-encoding"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java index ccfab744eb4974..4db2c4ae608257 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java @@ -22,9 +22,10 @@ /** * Intent module. Launch other activities or open URLs. */ -@ReactModule(name = "ShareModule") +@ReactModule(name = ShareModule.NAME) public class ShareModule extends ReactContextBaseJavaModule { + public static final String NAME = "ShareModule"; /* package */ static final String ACTION_SHARED = "sharedAction"; /* package */ static final String ERROR_INVALID_CONTENT = "E_INVALID_CONTENT"; /* package */ static final String ERROR_UNABLE_TO_OPEN_DIALOG = "E_UNABLE_TO_OPEN_DIALOG"; @@ -35,7 +36,7 @@ public ShareModule(ReactApplicationContext reactContext) { @Override public String getName() { - return "ShareModule"; + return NAME; } /** From e5c96a85fc947ae3d6195441b82bb6247ff35dce Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 7 Jun 2019 17:17:16 -0700 Subject: [PATCH 145/330] Fix layoutTime calculation Summary: LayoutTime calculation is also trivially wrong. Quick fix. Reviewed By: shergin Differential Revision: D15725167 fbshipit-source-id: b06672b9df9cbaa6c54aa97a4c0b58a43f70d5b2 --- ReactCommon/fabric/mounting/MountingTelemetry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/mounting/MountingTelemetry.cpp b/ReactCommon/fabric/mounting/MountingTelemetry.cpp index 5f5bdf30ab7a2d..121c51e455100e 100644 --- a/ReactCommon/fabric/mounting/MountingTelemetry.cpp +++ b/ReactCommon/fabric/mounting/MountingTelemetry.cpp @@ -47,7 +47,7 @@ int64_t MountingTelemetry::getCommitTime() const { int64_t MountingTelemetry::getLayoutTime() const { assert(layoutStartTime_ != kUndefinedTime); assert(layoutEndTime_ != kUndefinedTime); - return layoutEndTime_ - layoutEndTime_; + return layoutEndTime_ - layoutStartTime_; } int64_t MountingTelemetry::getCommitStartTime() const { From 9c76e14b07cd83c1f481ff7457c965c86256c304 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Sat, 8 Jun 2019 00:41:06 -0700 Subject: [PATCH 146/330] Turn FBMainReactPackage into a TurboReactPackage Summary: `ReactTurboModuleManagerDelegate` only understands `TurboReactPackage`s. So, we need to convert `FBMainReactPackage` and all its dependent packages into `TurboReactPackage`. Reviewed By: fkgozali Differential Revision: D15711546 fbshipit-source-id: df626d542a6477b116c867299219156423c6364a --- .../react/testing/StringRecordingModule.java | 4 +- .../java/com/facebook/react/tests/core/BUCK | 2 + .../react/tests/core/ReactRootViewTest.java | 58 +++- .../react/shell/MainReactPackage.java | 324 +++++++----------- 4 files changed, 176 insertions(+), 212 deletions(-) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java index 6dd70646f0d77c..9103a265ec5deb 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java @@ -19,11 +19,13 @@ */ public class StringRecordingModule extends BaseJavaModule { + public static final String NAME = "Recording"; + private final List mCalls = new ArrayList(); @Override public String getName() { - return "Recording"; + return NAME; } @ReactMethod diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK index 5d3380b6f8b05a..d14a43f82cfef1 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK @@ -22,6 +22,8 @@ rn_android_library( react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/module/model:model"), react_native_target("java/com/facebook/react/shell:shell"), react_native_target("java/com/facebook/react/uimanager:uimanager"), ]) + ([ diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java index acc108fb3c39dc..6f6d1495385305 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java @@ -26,11 +26,16 @@ import com.facebook.react.uimanager.PixelUtil; import java.util.ArrayList; import java.util.List; +import java.util.HashMap; +import java.util.Map; import javax.inject.Provider; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.module.annotations.ReactModule; @RunWith(AndroidJUnit4.class) public class ReactRootViewTest { @@ -42,18 +47,47 @@ private interface ReactRootViewTestModule extends JavaScriptModule { final StringRecordingModule mRecordingModule = new StringRecordingModule(); final ReactPackage mReactPackage = new MainReactPackage() { @Override - public List getNativeModules(ReactApplicationContext context) { - List modules = new ArrayList<>(super.getNativeModules(context)); - modules.add( - ModuleSpec.nativeModuleSpec( - StringRecordingModule.class, - new Provider() { - @Override - public NativeModule get() { - return mRecordingModule; - } - })); - return modules; + public NativeModule getModule(String name, ReactApplicationContext context) { + if (name.equals(StringRecordingModule.NAME)) { + return mRecordingModule; + } + + return super.getModule(name, context); + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + final ReactModuleInfoProvider provider = super.getReactModuleInfoProvider(); + + return new ReactModuleInfoProvider() { + private Map mModuleInfos = null; + + @Override + public Map getReactModuleInfos() { + if (mModuleInfos != null) { + return mModuleInfos; + } + + mModuleInfos = new HashMap<>(); + mModuleInfos.putAll(provider.getReactModuleInfos()); + + Class moduleClass = StringRecordingModule.class; + ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class); + + mModuleInfos.put( + reactModule.name(), + new ReactModuleInfo( + reactModule.name(), + moduleClass.getName(), + reactModule.canOverrideExistingModule(), + reactModule.needsEagerInit(), + reactModule.hasConstants(), + reactModule.isCxxModule(), + false)); + + return mModuleInfos; + } + }; } }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index cf1f81113f8028..bb0d8ee52e1eb6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -63,7 +63,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.annotation.Nullable; import javax.inject.Provider; +import com.facebook.react.TurboReactPackage; +import com.facebook.react.ViewManagerOnDemandReactPackage; +import java.util.Map; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.annotations.ReactModule; +import java.util.HashMap; /** * Package defining basic modules and view managers. @@ -93,9 +100,8 @@ ToastModule.class, VibrationModule.class, WebSocketModule.class, - }) -public class MainReactPackage extends LazyReactPackage { +public class MainReactPackage extends TurboReactPackage { private MainPackageConfig mConfig; @@ -110,201 +116,60 @@ public MainReactPackage(MainPackageConfig config) { } @Override - public List getNativeModules(final ReactApplicationContext context) { - return Arrays.asList( - ModuleSpec.nativeModuleSpec( - AccessibilityInfoModule.class, - new Provider() { - @Override - public NativeModule get() { - return new AccessibilityInfoModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - AppStateModule.class, - new Provider() { - @Override - public NativeModule get() { - return new AppStateModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - BlobModule.class, - new Provider() { - @Override - public NativeModule get() { - return new BlobModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - FileReaderModule.class, - new Provider() { - @Override - public NativeModule get() { - return new FileReaderModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - AsyncStorageModule.class, - new Provider() { - @Override - public NativeModule get() { - return new AsyncStorageModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - CameraRollManager.class, - new Provider() { - @Override - public NativeModule get() { - return new CameraRollManager(context); - } - }), - ModuleSpec.nativeModuleSpec( - ClipboardModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ClipboardModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - DatePickerDialogModule.class, - new Provider() { - @Override - public NativeModule get() { - return new DatePickerDialogModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - DialogModule.class, - new Provider() { - @Override - public NativeModule get() { - return new DialogModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - FrescoModule.class, - new Provider() { - @Override - public NativeModule get() { - return new FrescoModule( - context, true, mConfig != null ? mConfig.getFrescoConfig() : null); - } - }), - ModuleSpec.nativeModuleSpec( - I18nManagerModule.class, - new Provider() { - @Override - public NativeModule get() { - return new I18nManagerModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ImageEditingManager.class, - new Provider() { - @Override - public NativeModule get() { - return new ImageEditingManager(context); - } - }), - ModuleSpec.nativeModuleSpec( - ImageLoaderModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ImageLoaderModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ImageStoreManager.class, - new Provider() { - @Override - public NativeModule get() { - return new ImageStoreManager(context); - } - }), - ModuleSpec.nativeModuleSpec( - IntentModule.class, - new Provider() { - @Override - public NativeModule get() { - return new IntentModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - NativeAnimatedModule.class, - new Provider() { - @Override - public NativeModule get() { - return new NativeAnimatedModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - NetworkingModule.class, - new Provider() { - @Override - public NativeModule get() { - return new NetworkingModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - PermissionsModule.class, - new Provider() { - @Override - public NativeModule get() { - return new PermissionsModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ShareModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ShareModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - StatusBarModule.class, - new Provider() { - @Override - public NativeModule get() { - return new StatusBarModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - TimePickerDialogModule.class, - new Provider() { - @Override - public NativeModule get() { - return new TimePickerDialogModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ToastModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ToastModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - VibrationModule.class, - new Provider() { - @Override - public NativeModule get() { - return new VibrationModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - WebSocketModule.class, - new Provider() { - @Override - public NativeModule get() { - return new WebSocketModule(context); - } - })); + public @Nullable NativeModule getModule(String name, ReactApplicationContext context) { + switch (name) { + case AccessibilityInfoModule.NAME: + return new AccessibilityInfoModule(context); + case AppStateModule.NAME: + return new AppStateModule(context); + case BlobModule.NAME: + return new BlobModule(context); + case FileReaderModule.NAME: + return new FileReaderModule(context); + case AsyncStorageModule.NAME: + return new AsyncStorageModule(context); + case CameraRollManager.NAME: + return new CameraRollManager(context); + case ClipboardModule.NAME: + return new ClipboardModule(context); + case DatePickerDialogModule.FRAGMENT_TAG: + return new DatePickerDialogModule(context); + case DialogModule.NAME: + return new DialogModule(context); + case FrescoModule.NAME: + return new FrescoModule( + context, true, mConfig != null ? mConfig.getFrescoConfig() : null); + case I18nManagerModule.NAME: + return new I18nManagerModule(context); + case ImageEditingManager.NAME: + return new ImageEditingManager(context); + case ImageLoaderModule.NAME: + return new ImageLoaderModule(context); + case ImageStoreManager.NAME: + return new ImageStoreManager(context); + case IntentModule.NAME: + return new IntentModule(context); + case NativeAnimatedModule.NAME: + return new NativeAnimatedModule(context); + case NetworkingModule.NAME: + return new NetworkingModule(context); + case PermissionsModule.NAME: + return new PermissionsModule(context); + case ShareModule.NAME: + return new ShareModule(context); + case StatusBarModule.NAME: + return new StatusBarModule(context); + case TimePickerDialogModule.FRAGMENT_TAG: + return new TimePickerDialogModule(context); + case ToastModule.NAME: + return new ToastModule(context); + case VibrationModule.NAME: + return new VibrationModule(context); + case WebSocketModule.NAME: + return new WebSocketModule(context); + default: + return null; + } } @Override @@ -343,7 +208,68 @@ public List createViewManagers(ReactApplicationContext reactContext @Override public ReactModuleInfoProvider getReactModuleInfoProvider() { - // This has to be done via reflection or we break open source. - return LazyReactPackage.getReactModuleInfoProviderViaReflection(this); + try { + Class reactModuleInfoProviderClass = + Class.forName("com.facebook.react.MainReactPackage$$ReactModuleInfoProvider"); + return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance(); + } catch (ClassNotFoundException e) { + // In OSS case, the annotation processor does not run. We fall back on creating this byhand + Class[] moduleList = + new Class[] { + AccessibilityInfoModule.class, + AppStateModule.class, + BlobModule.class, + FileReaderModule.class, + AsyncStorageModule.class, + CameraRollManager.class, + ClipboardModule.class, + DatePickerDialogModule.class, + DialogModule.class, + FrescoModule.class, + I18nManagerModule.class, + ImageEditingManager.class, + ImageLoaderModule.class, + ImageStoreManager.class, + IntentModule.class, + NativeAnimatedModule.class, + NetworkingModule.class, + PermissionsModule.class, + ShareModule.class, + StatusBarModule.class, + TimePickerDialogModule.class, + ToastModule.class, + VibrationModule.class, + WebSocketModule.class + }; + + final Map reactModuleInfoMap = new HashMap<>(); + for (Class moduleClass : moduleList) { + ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class); + + reactModuleInfoMap.put( + reactModule.name(), + new ReactModuleInfo( + reactModule.name(), + moduleClass.getName(), + reactModule.canOverrideExistingModule(), + reactModule.needsEagerInit(), + reactModule.hasConstants(), + reactModule.isCxxModule(), + false)); + } + + return new ReactModuleInfoProvider() { + @Override + public Map getReactModuleInfos() { + return reactModuleInfoMap; + } + }; + } catch (InstantiationException e) { + throw new RuntimeException( + "No ReactModuleInfoProvider for CoreModulesPackage$$ReactModuleInfoProvider", e); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "No ReactModuleInfoProvider for CoreModulesPackage$$ReactModuleInfoProvider", e); + } } } From 6236798a3fce3c4bdbd8ce340e20db16cd67e03a Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sat, 8 Jun 2019 07:10:41 -0700 Subject: [PATCH 147/330] Create feature flag to log extra data in ReactWebView Summary: This diff creates a new react feature flag to enable extra logging on React Web Views Reviewed By: RSNara Differential Revision: D15729871 fbshipit-source-id: 931d4a1b022c6a405228bf896b50ecc7a44478d1 --- .../java/com/facebook/react/config/ReactFeatureFlags.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index 94ae2364c6bb49..d6401919987305 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -43,4 +43,10 @@ public class ReactFeatureFlags { * {@link com.facebook.react.uimanager.NativeViewHierarchyManager dropView} */ public static boolean logDroppedViews = false; + + /* + * This feature flag enables extra logging on ReactWebViews. + * Default value is false. + */ + public static boolean enableExtraWebViewLogs = false; } From 47a17fb69ef16ba92ad587ddd3fb448f09692c4d Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 8 Jun 2019 22:37:26 -0700 Subject: [PATCH 148/330] Fabric: Fixed incorrect SchedulerToolbox initialization in RCTSurfacePresenter Summary: We have to use a getter instead of an ivar to enable lazy initialization of ContextContainer. Reviewed By: mdvacca Differential Revision: D15731877 fbshipit-source-id: eb4d0e70c337026a91cb12a3eb26ed4d94f39f9f --- React/Fabric/RCTSurfacePresenter.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index adc049828ad2cb..17f4491a7c582a 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -197,7 +197,7 @@ - (RCTScheduler *)_scheduler auto runtimeExecutor = [self _runtimeExecutor]; auto toolbox = SchedulerToolbox{}; - toolbox.contextContainer = _contextContainer; + toolbox.contextContainer = self.contextContainer; toolbox.componentRegistryFactory = componentRegistryFactory; toolbox.runtimeExecutor = runtimeExecutor; From c94d7d520fb2b7509d4d5fca3976d9e66616308e Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Mon, 10 Jun 2019 01:38:20 -0700 Subject: [PATCH 149/330] Remove ToolbarAndroid Summary: After upgrading `react-native-gesture-handler` in D15701771, we can finally remove this :) Reviewed By: rubennorte Differential Revision: D15713072 fbshipit-source-id: 5039478f211a9bdb6ba0d17bed0841e188d00b46 --- Libraries/react-native/react-native-implementation.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 1fb35b409b6bdd..bc20dfac8f27c2 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -332,10 +332,6 @@ module.exports = { get ViewPropTypes() { return require('../DeprecatedPropTypes/DeprecatedViewPropTypes'); }, - // TODO(cpojer): Temporary fix for missing Toolbar - get ToolbarAndroid() { - return require('../Components/UnimplementedViews/UnimplementedView'); - }, }; if (__DEV__) { From b6dc9587e61035f812b8be5bb47c79bd133c70b7 Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Mon, 10 Jun 2019 01:43:25 -0700 Subject: [PATCH 150/330] add node layout event and pass it java layer Summary: Listen to NodeLayout event and passes this event callback to java layer along with the information whether layout or measure was done in this pass Reviewed By: davidaurelio Differential Revision: D15696021 fbshipit-source-id: 8c5ca69330a9baca26b77052d4965cc67fe97c75 --- .../src/main/java/com/facebook/yoga/YogaEventListener.java | 2 ++ ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java index 97791224577d67..cc7e9ebd0da671 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java @@ -12,4 +12,6 @@ public interface YogaEventListener { void onNodeMeasure(YogaNode node); + void onNodeLayout(YogaNode node, boolean performLayout); + } diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index c46104be1d33e1..6c739a069e0999 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -3670,7 +3670,7 @@ bool YGLayoutNodeInternal( YGMarkerLayoutData& layoutMarkerData, void* const layoutContext) { #ifdef YG_ENABLE_EVENTS - Event::publish(node); + Event::publish(node, {performLayout, layoutContext}); #endif YGLayout* layout = &node->getLayout(); diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index bff8dbfd8952fc..9dcd73b6a0fa59 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -82,5 +82,11 @@ struct Event::TypedData { void* layoutContext; }; +template <> +struct Event::TypedData { + bool performLayout; + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From 2c1fd6f764f92669351713a6373a113ea6cb5da2 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 10 Jun 2019 03:26:44 -0700 Subject: [PATCH 151/330] Add codegen flowtypes to UnimplementedNativeView Summary: This diff adds the generated view config for UnimplementedNativeView Note: I believe this component was created in JS just for the codegen because it's unused anywhere Reviewed By: cpojer Differential Revision: D15494268 fbshipit-source-id: 8d17465fe59861a299b76565d6edbaf168f45906 --- .../UnimplementedNativeView.js | 29 ------------------- .../UnimplementedNativeViewNativeComponent.js | 27 +++++++++++++++++ 2 files changed, 27 insertions(+), 29 deletions(-) delete mode 100644 Libraries/Components/UnimplementedViews/UnimplementedNativeView.js create mode 100644 Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js diff --git a/Libraries/Components/UnimplementedViews/UnimplementedNativeView.js b/Libraries/Components/UnimplementedViews/UnimplementedNativeView.js deleted file mode 100644 index 9e1d5f64af019c..00000000000000 --- a/Libraries/Components/UnimplementedViews/UnimplementedNativeView.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - -import type {ViewProps} from '../View/ViewPropTypes'; -import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; - -type NativeProps = $ReadOnly<{| - ...ViewProps, - name?: ?string, - style?: ?ViewStyleProp, -|}>; - -type UnimplementedViewNativeType = Class>; - -module.exports = ((requireNativeComponent( - 'UnimplementedNativeView', -): any): UnimplementedViewNativeType); diff --git a/Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js b/Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js new file mode 100644 index 00000000000000..6898d1acd699db --- /dev/null +++ b/Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +import type {WithDefault} from '../../Types/CodegenTypes'; +import type {ViewProps} from '../View/ViewPropTypes'; + +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; + +type NativeProps = $ReadOnly<{| + ...ViewProps, + name?: ?WithDefault, +|}>; + +// NOTE: This compoenent is not implemented in paper +// Do not include in paper builds +module.exports = codegenNativeComponent( + './UnimplementedNativeViewNativeViewConfig', +); From 5b7be95a1d00f813223c97ce8fe69118951ad412 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 10 Jun 2019 03:26:44 -0700 Subject: [PATCH 152/330] Use generated view config for iOS Switch Summary: Adds a generated view config for iOS Switch Note: this required some refactoring because the SwitchNativeComponent file included both iOS and android componets, so I broke them out into: - AndroidSwitchNativeComponent (not generated) - SwitchNativeComponent (generated) The schema that we're using is for the iOS version so that's the config that's generated here Reviewed By: cpojer Differential Revision: D15495402 fbshipit-source-id: 07b3bc9c780cbf8f6cbf66e976e15981cefcadfa --- .../Switch/AndroidSwitchNativeComponent.js | 48 ++++++++++ Libraries/Components/Switch/Switch.js | 93 ++++++++++++------- .../Switch/SwitchNativeComponent.js | 66 +++++-------- Libraries/Types/CoreEventTypes.js | 6 -- 4 files changed, 129 insertions(+), 84 deletions(-) create mode 100644 Libraries/Components/Switch/AndroidSwitchNativeComponent.js diff --git a/Libraries/Components/Switch/AndroidSwitchNativeComponent.js b/Libraries/Components/Switch/AndroidSwitchNativeComponent.js new file mode 100644 index 00000000000000..c8c9bba9ada41f --- /dev/null +++ b/Libraries/Components/Switch/AndroidSwitchNativeComponent.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +const {NativeComponent} = require('../../Renderer/shims/ReactNative'); + +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + +import type {SyntheticEvent} from '../../Types/CoreEventTypes'; +import type {ViewProps} from '../View/ViewPropTypes'; + +type SwitchChangeEvent = SyntheticEvent< + $ReadOnly<{| + value: boolean, + |}>, +>; + +type NativeProps = $ReadOnly<{| + ...ViewProps, + + // Props + disabled?: ?boolean, + enabled?: ?boolean, + thumbColor?: ?string, + trackColorForFalse?: ?string, + trackColorForTrue?: ?string, + value?: ?boolean, + on?: ?boolean, + thumbTintColor?: ?string, + trackTintColor?: ?string, + + // Events + onChange?: ?(event: SwitchChangeEvent) => mixed, +|}>; + +type SwitchNativeComponentType = Class>; + +module.exports = ((requireNativeComponent( + 'AndroidSwitch', +): any): SwitchNativeComponentType); diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js index d47c61b00b04b0..dfd4067e33063b 100644 --- a/Libraries/Components/Switch/Switch.js +++ b/Libraries/Components/Switch/Switch.js @@ -11,14 +11,20 @@ 'use strict'; const SwitchNativeComponent = require('./SwitchNativeComponent'); +const AndroidSwitchNativeComponent = require('./AndroidSwitchNativeComponent'); const Platform = require('../../Utilities/Platform'); const React = require('react'); const StyleSheet = require('../../StyleSheet/StyleSheet'); -import type {SwitchChangeEvent} from '../../Types/CoreEventTypes'; +import type {SyntheticEvent} from '../../Types/CoreEventTypes'; import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -import type {NativeAndroidProps, NativeIOSProps} from './SwitchNativeComponent'; + +type SwitchChangeEvent = SyntheticEvent< + $ReadOnly<{| + value: boolean, + |}>, +>; export type Props = $ReadOnly<{| ...ViewProps, @@ -83,7 +89,9 @@ export type Props = $ReadOnly<{| * supplied `value` prop instead of the expected result of any user actions. */ class Switch extends React.Component { - _nativeSwitchRef: ?React.ElementRef; + _nativeSwitchRef: ?React.ElementRef< + typeof SwitchNativeComponent | typeof AndroidSwitchNativeComponent, + >; render() { const { @@ -130,37 +138,50 @@ class Switch extends React.Component { } } - const platformProps = - Platform.OS === 'android' - ? ({ - enabled: disabled !== true, - on: value === true, - style, - thumbTintColor: _thumbColor, - trackColorForFalse: _trackColorForFalse, - trackColorForTrue: _trackColorForTrue, - trackTintColor: - value === true ? _trackColorForTrue : _trackColorForFalse, - }: NativeAndroidProps) - : ({ - disabled, - onTintColor: _trackColorForTrue, - style: StyleSheet.compose( - {height: 31, width: 51}, - StyleSheet.compose( - style, - ios_backgroundColor == null - ? null - : { - backgroundColor: ios_backgroundColor, - borderRadius: 16, - }, - ), - ), - thumbTintColor: _thumbColor, - tintColor: _trackColorForFalse, - value: value === true, - }: NativeIOSProps); + if (Platform.OS === 'android') { + const platformProps = { + enabled: disabled !== true, + on: value === true, + style, + thumbTintColor: _thumbColor, + trackColorForFalse: _trackColorForFalse, + trackColorForTrue: _trackColorForTrue, + trackTintColor: + value === true ? _trackColorForTrue : _trackColorForFalse, + }; + + return ( + + ); + } + + const platformProps = { + disabled, + onTintColor: _trackColorForTrue, + style: StyleSheet.compose( + {height: 31, width: 51}, + StyleSheet.compose( + style, + ios_backgroundColor == null + ? null + : { + backgroundColor: ios_backgroundColor, + borderRadius: 16, + }, + ), + ), + thumbTintColor: _thumbColor, + tintColor: _trackColorForFalse, + value: value === true, + }; return ( { }; _handleSwitchNativeComponentRef = ( - ref: ?React.ElementRef, + ref: ?React.ElementRef< + typeof SwitchNativeComponent | typeof AndroidSwitchNativeComponent, + >, ) => { this._nativeSwitchRef = ref; }; diff --git a/Libraries/Components/Switch/SwitchNativeComponent.js b/Libraries/Components/Switch/SwitchNativeComponent.js index b3be4dfaa12d22..b9c113b3b27cb0 100644 --- a/Libraries/Components/Switch/SwitchNativeComponent.js +++ b/Libraries/Components/Switch/SwitchNativeComponent.js @@ -10,55 +10,35 @@ 'use strict'; -const Platform = require('../../Utilities/Platform'); -const ReactNative = require('../../Renderer/shims/ReactNative'); - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - -import type {SwitchChangeEvent} from '../../Types/CoreEventTypes'; +import type {BubblingEvent, WithDefault} from '../../Types/CodegenTypes'; +import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -type SwitchProps = $ReadOnly<{| - ...ViewProps, - disabled?: ?boolean, - onChange?: ?(event: SwitchChangeEvent) => mixed, - thumbColor?: ?string, - trackColorForFalse?: ?string, - trackColorForTrue?: ?string, - value?: ?boolean, -|}>; - -// @see ReactSwitchManager.java -export type NativeAndroidProps = $ReadOnly<{| - ...SwitchProps, +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; - enabled?: ?boolean, - on?: ?boolean, - thumbTintColor?: ?string, - trackTintColor?: ?string, +type SwitchChangeEvent = $ReadOnly<{| + value: boolean, |}>; -// @see RCTSwitchManager.m -export type NativeIOSProps = $ReadOnly<{| - ...SwitchProps, +type NativeProps = $ReadOnly<{| + ...ViewProps, - onTintColor?: ?string, - thumbTintColor?: ?string, - tintColor?: ?string, -|}>; + // Props + disabled?: ?WithDefault, + value?: ?WithDefault, + tintColor?: ?ColorValue, + onTintColor?: ?ColorValue, + thumbTintColor?: ?ColorValue, -type SwitchNativeComponentType = Class< - ReactNative.NativeComponent< - $ReadOnly<{| - ...NativeAndroidProps, - ...NativeIOSProps, - |}>, - >, ->; + // Deprecated props + thumbColor?: ?ColorValue, + trackColorForFalse?: ?ColorValue, + trackColorForTrue?: ?ColorValue, -const SwitchNativeComponent: SwitchNativeComponentType = - Platform.OS === 'android' - ? (requireNativeComponent('AndroidSwitch'): any) - : (requireNativeComponent('RCTSwitch'): any); + // Events + onChange?: ?(event: BubblingEvent) => mixed, +|}>; -module.exports = SwitchNativeComponent; +module.exports = codegenNativeComponent('Switch', { + isDeprecatedPaperComponentNameRCT: true, +}); diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index abe3ca172f0181..a8dd79ea17f5d6 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -129,9 +129,3 @@ export type ScrollEvent = SyntheticEvent< responderIgnoreScroll?: boolean, |}>, >; - -export type SwitchChangeEvent = SyntheticEvent< - $ReadOnly<{| - value: boolean, - |}>, ->; From d0792d4b8ac42711dfd9fccb782f16e72ce3e335 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 10 Jun 2019 03:27:07 -0700 Subject: [PATCH 153/330] Add ReactFragment for Android Summary: React Native on Android has currently been focused and targeted at using an Activity for its main form of instantiation. While this has probably worked for most companies and developers, you lose some of the modularity of a more cohesive application when working in a "brown-field" project that is currently native. This hurts more companies that are looking to adopt React Native and slowly implement it in a fully native application. A lot of developers follow Android's guidelines of using Fragments in their projects, even if it is a debated subject in the Android community, and this addition will allow others to embrace React Native more freely. (I even assume it could help with managing navigation state in applications that contain a decent amount of Native code and would be appreciated in those projects. Such as sharing the Toolbar, TabBar, ViewPager, etc in Native Android) Even with this addition, a developer will still need to host the fragment in an activity, but now that activity can contain native logic like a Drawer, Tabs, ViewPager, etc. Test plan (required) We have been using this class at Hudl for over a couple of months and have found it valuable. If the community agrees on the addition, I can add documentation to the Android sections to include notes about the potential of this Fragment. If the community agrees on the addition, I can update one or more of the examples in the /Examples folder and make use of the Fragment, or even create a new example that uses a native layout manager like Drawer, Tabs, Viewpager, etc) Make sure tests pass on both Travis and Circle CI. _To Note:_ There is also talk of using React Native inside Android Fragment's without any legit documentation, this could help remedy some of that with more documentation included in this PR https://facebook.github.io/react-native/releases/0.26/docs/embedded-app-android.html#sharing-a-reactinstance-across-multiple-activities-fragments-in-your-app Others have also requested something similar and have a half-baked solution as well http://stackoverflow.com/questions/35221447/react-native-inside-a-fragment Release Notes [ANDROID][FEATURE][ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java] - Adds support for Android's Fragment system. This allows for a more hybrid application. Reviewed By: cpojer Differential Revision: D15731340 fbshipit-source-id: 74b7aaedcfd6ad6e074ff911cd7f18a5111caf5c --- .../facebook/react/ReactActivityDelegate.java | 68 ++---- .../com/facebook/react/ReactDelegate.java | 147 ++++++++++++ .../com/facebook/react/ReactFragment.java | 210 ++++++++++++++++++ 3 files changed, 371 insertions(+), 54 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java index c6534217a084e3..fcfbea9b4d37b2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java @@ -15,8 +15,7 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.Callback; -import com.facebook.react.devsupport.DoubleTapReloadRecognizer; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; +import com.facebook.react.uimanager.RootView; import com.facebook.react.modules.core.PermissionListener; import javax.annotation.Nullable; @@ -31,10 +30,9 @@ public class ReactActivityDelegate { private final @Nullable Activity mActivity; private final @Nullable String mMainComponentName; - private @Nullable ReactRootView mReactRootView; - private @Nullable DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; private @Nullable PermissionListener mPermissionListener; private @Nullable Callback mPermissionsCallback; + private ReactDelegate mReactDelegate; @Deprecated public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) { @@ -52,7 +50,7 @@ public ReactActivityDelegate(ReactActivity activity, @Nullable String mainCompon } protected ReactRootView createRootView() { - return new ReactRootView(getContext()); + return mReactDelegate.createRootView(); } /** @@ -67,7 +65,7 @@ protected ReactNativeHost getReactNativeHost() { } public ReactInstanceManager getReactInstanceManager() { - return getReactNativeHost().getReactInstanceManager(); + return mReactDelegate.getReactInstanceManager(); } public String getMainComponentName() { @@ -76,36 +74,23 @@ public String getMainComponentName() { protected void onCreate(Bundle savedInstanceState) { String mainComponentName = getMainComponentName(); - if (mainComponentName != null) { + mReactDelegate = new ReactDelegate(getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()); + if (mMainComponentName != null) { loadApp(mainComponentName); } - mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } protected void loadApp(String appKey) { - if (mReactRootView != null) { - throw new IllegalStateException("Cannot loadApp while app is already running."); - } - mReactRootView = createRootView(); - mReactRootView.startReactApplication( - getReactNativeHost().getReactInstanceManager(), - appKey, - getLaunchOptions()); - getPlainActivity().setContentView(mReactRootView); + mReactDelegate.loadApp(appKey); + getPlainActivity().setContentView(mReactDelegate.getReactRootView()); } protected void onPause() { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onHostPause(getPlainActivity()); - } + mReactDelegate.onHostPause(); } protected void onResume() { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onHostResume( - getPlainActivity(), - (DefaultHardwareBackBtnHandler) getPlainActivity()); - } + mReactDelegate.onHostResume(); if (mPermissionsCallback != null) { mPermissionsCallback.invoke(); @@ -114,20 +99,11 @@ protected void onResume() { } protected void onDestroy() { - if (mReactRootView != null) { - mReactRootView.unmountReactApplication(); - mReactRootView = null; - } - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onHostDestroy(getPlainActivity()); - } + mReactDelegate.onHostDestroy(); } public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager() - .onActivityResult(getPlainActivity(), requestCode, resultCode, data); - } + mReactDelegate.onActivityResult(requestCode, resultCode, data, true); } public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -141,19 +117,7 @@ && getReactNativeHost().getUseDeveloperSupport() } public boolean onKeyUp(int keyCode, KeyEvent event) { - if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) { - if (keyCode == KeyEvent.KEYCODE_MENU) { - getReactNativeHost().getReactInstanceManager().showDevOptionsDialog(); - return true; - } - boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer) - .didDoubleTapR(keyCode, getPlainActivity().getCurrentFocus()); - if (didDoubleTapR) { - getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS(); - return true; - } - } - return false; + return mReactDelegate.shouldShowDevMenuOrReload(keyCode, event); } public boolean onKeyLongPress(int keyCode, KeyEvent event) { @@ -167,11 +131,7 @@ && getReactNativeHost().getUseDeveloperSupport() } public boolean onBackPressed() { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onBackPressed(); - return true; - } - return false; + return mReactDelegate.onBackPressed(); } public boolean onNewIntent(Intent intent) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java new file mode 100644 index 00000000000000..e219c8be3c6626 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.KeyEvent; + +import com.facebook.infer.annotation.Assertions; +import com.facebook.react.devsupport.DoubleTapReloadRecognizer; +import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; + +import javax.annotation.Nullable; + +/** + * A delegate for handling React Application support. This delegate is unaware whether it is used in + * an {@link Activity} or a {@link android.app.Fragment}. + */ +public class ReactDelegate { + + private final Activity mActivity; + private ReactRootView mReactRootView; + + @Nullable + private final String mMainComponentName; + + @Nullable + private Bundle mLaunchOptions; + + @Nullable + private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; + + private ReactNativeHost mReactNativeHost; + + + public ReactDelegate(Activity activity, ReactNativeHost reactNativeHost, @Nullable String appKey, @Nullable Bundle launchOptions) { + mActivity = activity; + mMainComponentName = appKey; + mLaunchOptions = launchOptions; + mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); + mReactNativeHost = reactNativeHost; + } + + public void onHostResume() { + if (getReactNativeHost().hasInstance()) { + if (mActivity instanceof DefaultHardwareBackBtnHandler) { + getReactNativeHost().getReactInstanceManager().onHostResume(mActivity, (DefaultHardwareBackBtnHandler) mActivity); + } else { + throw new ClassCastException("Host Activity does not implement DefaultHardwareBackBtnHandler"); + } + } + } + + public void onHostPause() { + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onHostPause(mActivity); + } + } + + public void onHostDestroy() { + if (mReactRootView != null) { + mReactRootView.unmountReactApplication(); + mReactRootView = null; + } + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onHostDestroy(mActivity); + } + } + + public boolean onBackPressed() { + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onBackPressed(); + return true; + } + return false; + } + + public void onActivityResult(int requestCode, int resultCode, Intent data, boolean shouldForwardToReactInstance) { + if (getReactNativeHost().hasInstance() && shouldForwardToReactInstance) { + getReactNativeHost().getReactInstanceManager().onActivityResult(mActivity, requestCode, resultCode, data); + } + } + + public void loadApp() { + loadApp(mMainComponentName); + } + + public void loadApp(String appKey) { + if (mReactRootView != null) { + throw new IllegalStateException("Cannot loadApp while app is already running."); + } + mReactRootView = createRootView(); + mReactRootView.startReactApplication( + getReactNativeHost().getReactInstanceManager(), + appKey, + mLaunchOptions); + + } + + public ReactRootView getReactRootView() { + return mReactRootView; + } + + + protected ReactRootView createRootView() { + return new ReactRootView(mActivity); + } + + /** + * Handles delegating the {@link Activity#onKeyUp(int, KeyEvent)} method to determine whether + * the application should show the developer menu or should reload the React Application. + * + * @return true if we consume the event and either shoed the develop menu or reloaded the application. + */ + public boolean shouldShowDevMenuOrReload(int keyCode, KeyEvent event) { + if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) { + if (keyCode == KeyEvent.KEYCODE_MENU) { + getReactNativeHost().getReactInstanceManager().showDevOptionsDialog(); + return true; + } + boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer).didDoubleTapR(keyCode, mActivity.getCurrentFocus()); + if (didDoubleTapR) { + getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS(); + return true; + } + } + return false; + } + + /** + * Get the {@link ReactNativeHost} used by this app. + */ + private ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + public ReactInstanceManager getReactInstanceManager() { + return getReactNativeHost().getReactInstanceManager(); + } + +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java b/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java new file mode 100644 index 00000000000000..6673c8955276f6 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java @@ -0,0 +1,210 @@ + +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +package com.facebook.react; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.facebook.react.modules.core.PermissionAwareActivity; +import com.facebook.react.modules.core.PermissionListener; + +import javax.annotation.Nullable; + +import androidx.fragment.app.Fragment; + +/** +* Fragment for creating a React View. This allows the developer to "embed" a React Application +* inside native components such as a Drawer, ViewPager, etc. +*/ +public class ReactFragment extends Fragment implements PermissionAwareActivity { + +private static final String ARG_COMPONENT_NAME = "arg_component_name"; +private static final String ARG_LAUNCH_OPTIONS = "arg_launch_options"; + +private ReactDelegate mReactDelegate; + +@Nullable +private PermissionListener mPermissionListener; + + +public ReactFragment() { + // Required empty public constructor +} + +/** + * @param componentName The name of the react native component + * @return A new instance of fragment ReactFragment. + */ +private static ReactFragment newInstance(String componentName, Bundle launchOptions) { + ReactFragment fragment = new ReactFragment(); + Bundle args = new Bundle(); + args.putString(ARG_COMPONENT_NAME, componentName); + args.putBundle(ARG_LAUNCH_OPTIONS, launchOptions); + fragment.setArguments(args); + return fragment; +} + +// region Lifecycle +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + String mainComponentName = null; + Bundle launchOptions = null; + if (getArguments() != null) { + mainComponentName = getArguments().getString(ARG_COMPONENT_NAME); + launchOptions = getArguments().getBundle(ARG_LAUNCH_OPTIONS); + } + if (mainComponentName == null) { + throw new IllegalStateException("Cannot loadApp if component name is null"); + } + mReactDelegate = new ReactDelegate(getActivity(), getReactNativeHost(), mainComponentName, launchOptions); +} + +/** + * Get the {@link ReactNativeHost} used by this app. By default, assumes + * {@link Activity#getApplication()} is an instance of {@link ReactApplication} and calls + * {@link ReactApplication#getReactNativeHost()}. Override this method if your application class + * does not implement {@code ReactApplication} or you simply have a different mechanism for + * storing a {@code ReactNativeHost}, e.g. as a static field somewhere. + */ +protected ReactNativeHost getReactNativeHost() { + return ((ReactApplication) getActivity().getApplication()).getReactNativeHost(); +} + +@Override +public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mReactDelegate.loadApp(); + return mReactDelegate.getReactRootView(); +} + +@Override +public void onResume() { + super.onResume(); + mReactDelegate.onHostResume(); +} + +@Override +public void onPause() { + super.onPause(); + mReactDelegate.onHostPause(); +} + +@Override +public void onDestroy() { + super.onDestroy(); + mReactDelegate.onHostDestroy(); +} +// endregion + +@Override +public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + mReactDelegate.onActivityResult(requestCode, resultCode, data, false); +} + +/** + * Helper to forward hardware back presses to our React Native Host + * + * This must be called via a forward from your host Activity + * + */ +public boolean onBackPressed() { + return mReactDelegate.onBackPressed(); +} + +/** + * Helper to forward onKeyUp commands from our host Activity. + * This allows ReactFragment to handle double tap reloads and dev menus + * + * This must be called via a forward from your host Activity + * + * @param keyCode keyCode + * @param event event + * @return true if we handled onKeyUp + */ +public boolean onKeyUp(int keyCode, KeyEvent event) { + return mReactDelegate.shouldShowDevMenuOrReload(keyCode, event); +} + +@Override +public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (mPermissionListener != null && + mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { + mPermissionListener = null; + } +} + +@Override +public int checkPermission(String permission, int pid, int uid) { + return getActivity().checkPermission(permission, pid, uid); +} + +@TargetApi(Build.VERSION_CODES.M) +@Override +public int checkSelfPermission(String permission) { + return getActivity().checkSelfPermission(permission); +} + +@TargetApi(Build.VERSION_CODES.M) +@Override +public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) { + mPermissionListener = listener; + requestPermissions(permissions, requestCode); +} + +/** + * Builder class to help instantiate a ReactFragment + */ +public static class Builder { + + String mComponentName; + Bundle mLaunchOptions; + + public Builder() { + mComponentName = null; + mLaunchOptions = null; + } + + /** + * Set the Component name for our React Native instance. + * + * @param componentName The name of the component + * @return Builder + */ + public Builder setComponentName(String componentName) { + mComponentName = componentName; + return this; + } + + /** + * Set the Launch Options for our React Native instance. + * + * @param launchOptions launchOptions + * @return Builder + */ + public Builder setLaunchOptions(Bundle launchOptions) { + mLaunchOptions = launchOptions; + return this; + } + + public ReactFragment build() { + return ReactFragment.newInstance(mComponentName, mLaunchOptions); + } + +} +} From ae231c83220941e0e5aae74ff184467f75438452 Mon Sep 17 00:00:00 2001 From: Onti Vals Date: Mon, 10 Jun 2019 03:44:16 -0700 Subject: [PATCH 154/330] Scrolling fixes (#25105) Summary: Scrolling improvements in ReactAndroid: 1. Issue: With current ReactHorizontalScrollView behavior, it treats all views as focusable, regardless of if they are in view or not. This is fine for non-paged horizontal scroll view, but when paged this allows focus on elements that are not within the current page. Combined with logic to scroll to the focused view, this breaks the paging for ReactHorizontalScrollView. Fix: limit the focusable elements to only elements that are currently in view when ReactHorizontalScrollView has paging enabled 2. Issue: When keyboard is attached and user tries to navigate through Tab key, Scroll views do not scroll to the focused child. Since ReactScrollView handles layout changes on JS side, it does not call super.onlayout due to which mIsLayoutDirty flag in android ScrollView remains true and prevents scrolling to child when requestChildFocus is called. Fix: To fix the focus navigation, we are overriding requestChildFocus method in ReactScrollView. We are not checking any dirty layout flag and scrolling to child directly. This will fix focus navigation issue for KeyEvents which are not handled by android's ScrollView, for example: KEYCODE_TAB. Same applies to ReactHorizontalScrollView. 3. Set Android ScrollView to be non-focusable when scroll is disabled. Prior to this change, non-scrollable Scrollview would still be focusable, causing a poor keyboarding experience ## Changelog [Android] [Fixed] Scrolling improvements in ReactAndroid Pull Request resolved: https://github.com/facebook/react-native/pull/25105 Differential Revision: D15737563 Pulled By: mdvacca fbshipit-source-id: 0d57563415c68668dc1acb05fb3399e6645c9595 --- .../scroll/ReactHorizontalScrollView.java | 147 ++++++++++++++++++ .../react/views/scroll/ReactScrollView.java | 29 ++++ .../views/scroll/ReactScrollViewManager.java | 4 + 3 files changed, 180 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index 18687228c13142..4d97b76e90a475 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -18,6 +18,7 @@ import androidx.core.view.ViewCompat; import androidx.core.text.TextUtilsCompat; import android.util.Log; +import android.view.FocusFinder; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -37,6 +38,8 @@ import java.util.List; import java.util.Locale; import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; /** * Similar to {@link ReactScrollView} but only supports horizontal scrolling. @@ -72,6 +75,9 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements private boolean mSnapToStart = true; private boolean mSnapToEnd = true; private ReactViewBackgroundManager mReactBackgroundManager; + private boolean mPagedArrowScrolling = false; + + private final Rect mTempRect = new Rect(); public ReactHorizontalScrollView(Context context) { this(context, null); @@ -221,6 +227,82 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { scrollTo(getScrollX(), getScrollY()); } + /** + * Since ReactHorizontalScrollView handles layout changes on JS side, it does not call super.onlayout + * due to which mIsLayoutDirty flag in HorizontalScrollView remains true and prevents scrolling to child + * when requestChildFocus is called. + * Overriding this method and scrolling to child without checking any layout dirty flag. This will fix + * focus navigation issue for KeyEvents which are not handled in HorizontalScrollView, for example: KEYCODE_TAB. + */ + @Override + public void requestChildFocus(View child, View focused) { + if (focused != null && !mPagingEnabled) { + scrollToChild(focused); + } + super.requestChildFocus(child, focused); + } + + @Override + public void addFocusables(ArrayList views, int direction, int focusableMode) { + if (mPagingEnabled && !mPagedArrowScrolling) { + // Only add elements within the current page to list of focusables + ArrayList candidateViews = new ArrayList(); + super.addFocusables(candidateViews, direction, focusableMode); + for (View candidate : candidateViews) { + // We must also include the currently focused in the focusables list or focus search will always + // return the first element within the focusables list + if (isScrolledInView(candidate) || isPartiallyScrolledInView(candidate) || candidate.isFocused()) { + views.add(candidate); + } + } + } else { + super.addFocusables(views, direction, focusableMode); + } + } + + /** + * Calculates the x delta required to scroll the given descendent into view + */ + private int getScrollDelta(View descendent) { + descendent.getDrawingRect(mTempRect); + offsetDescendantRectToMyCoords(descendent, mTempRect); + return computeScrollDeltaToGetChildRectOnScreen(mTempRect); + } + + /** + * Returns whether the given descendent is scrolled fully in view + */ + private boolean isScrolledInView(View descendent) { + return getScrollDelta(descendent) == 0; + } + + + /** + * Returns whether the given descendent is partially scrolled in view + */ + private boolean isPartiallyScrolledInView(View descendent) { + int scrollDelta = getScrollDelta(descendent); + descendent.getDrawingRect(mTempRect); + return scrollDelta != 0 && Math.abs(scrollDelta) < mTempRect.width(); + } + + /** + * Returns whether the given descendent is "mostly" (>50%) scrolled in view + */ + private boolean isMostlyScrolledInView(View descendent) { + int scrollDelta = getScrollDelta(descendent); + descendent.getDrawingRect(mTempRect); + return scrollDelta != 0 && Math.abs(scrollDelta) < (mTempRect.width() / 2); + } + + private void scrollToChild(View child) { + int scrollDelta = getScrollDelta(child); + + if (scrollDelta != 0) { + scrollBy(scrollDelta, 0); + } + } + @Override protected void onScrollChanged(int x, int y, int oldX, int oldY) { super.onScrollChanged(x, y, oldX, oldY); @@ -263,6 +345,48 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } + @Override + public boolean pageScroll(int direction) { + boolean handled = super.pageScroll(direction); + + if (mPagingEnabled && handled) { + handlePostTouchScrolling(0, 0); + } + + return handled; + } + + @Override + public boolean arrowScroll(int direction) { + boolean handled = false; + + if (mPagingEnabled) { + mPagedArrowScrolling = true; + + if (getChildCount() > 0) { + View currentFocused = findFocus(); + View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction); + View rootChild = getChildAt(0); + if (rootChild != null && nextFocused != null && nextFocused.getParent() == rootChild) { + if (!isScrolledInView(nextFocused) && !isMostlyScrolledInView(nextFocused)) { + smoothScrollToNextPage(direction); + } + nextFocused.requestFocus(); + handled = true; + } else { + smoothScrollToNextPage(direction); + handled = true; + } + } + + mPagedArrowScrolling = false; + } else { + handled = super.arrowScroll(direction); + } + + return handled; + } + @Override public boolean onTouchEvent(MotionEvent ev) { if (!mScrollEnabled) { @@ -706,6 +830,29 @@ private void flingAndSnap(int velocityX) { } } + private void smoothScrollToNextPage(int direction) { + int width = getWidth(); + int currentX = getScrollX(); + + int page = currentX / width; + if (currentX % width != 0) { + page++; + } + + if (direction == View.FOCUS_LEFT) { + page = page - 1; + } else { + page = page + 1; + } + + if (page < 0) { + page = 0; + } + + smoothScrollTo(page * width, getScrollY()); + handlePostTouchScrolling(0, 0); + } + @Override public void setBackgroundColor(int color) { mReactBackgroundManager.setBackgroundColor(color); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java index e98c1864c36f55..de0fc82ee66b27 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java @@ -205,6 +205,35 @@ protected void onAttachedToWindow() { } } + /** + * Since ReactScrollView handles layout changes on JS side, it does not call super.onlayout + * due to which mIsLayoutDirty flag in ScrollView remains true and prevents scrolling to child + * when requestChildFocus is called. + * Overriding this method and scrolling to child without checking any layout dirty flag. This will fix + * focus navigation issue for KeyEvents which are not handled by ScrollView, for example: KEYCODE_TAB. + */ + @Override + public void requestChildFocus(View child, View focused) { + if (focused != null) { + scrollToChild(focused); + } + super.requestChildFocus(child, focused); + } + + private void scrollToChild(View child) { + Rect tempRect = new Rect(); + child.getDrawingRect(tempRect); + + /* Offset from child's local coordinates to ScrollView coordinates */ + offsetDescendantRectToMyCoords(child, tempRect); + + int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(tempRect); + + if (scrollDelta != 0) { + scrollBy(0, scrollDelta); + } + } + @Override protected void onScrollChanged(int x, int y, int oldX, int oldY) { super.onScrollChanged(x, y, oldX, oldY); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index afe0725e43cd05..fecbd151d0121a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -70,6 +70,10 @@ public ReactScrollView createViewInstance(ThemedReactContext context) { @ReactProp(name = "scrollEnabled", defaultBoolean = true) public void setScrollEnabled(ReactScrollView view, boolean value) { view.setScrollEnabled(value); + + // Set focusable to match whether scroll is enabled. This improves keyboarding + // experience by not making scrollview a tab stop when you cannot interact with it. + view.setFocusable(value); } @ReactProp(name = "showsVerticalScrollIndicator") From 782e8481a135009efc2902b4f13793142e8c95fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Mon, 10 Jun 2019 04:05:00 -0700 Subject: [PATCH 155/330] chore: upgrade CLI to 2.0.0-rc.1 (#25190) Summary: The RC1 of the CLI upgrades Metro to 0.54.1 to be compatible with 0.60 and master and fixes an issue with haste backwards compatibility. cc kelset ## Changelog [General] [Changed] - Bump CLI to 2.0.0-rc.1 Pull Request resolved: https://github.com/facebook/react-native/pull/25190 Differential Revision: D15737249 Pulled By: cpojer fbshipit-source-id: a39747620a7652507d29f5dadb6a4bdc9c1393f0 --- package.json | 6 +- yarn.lock | 423 ++++++++++----------------------------------------- 2 files changed, 86 insertions(+), 343 deletions(-) diff --git a/package.json b/package.json index 0a3190a401376a..109c9280d03259 100644 --- a/package.json +++ b/package.json @@ -82,9 +82,9 @@ }, "dependencies": { "@babel/runtime": "^7.0.0", - "@react-native-community/cli": "2.0.0-rc.0", - "@react-native-community/cli-platform-android": "2.0.0-rc.0", - "@react-native-community/cli-platform-ios": "2.0.0-rc.0", + "@react-native-community/cli": "2.0.0-rc.1", + "@react-native-community/cli-platform-android": "2.0.0-rc.1", + "@react-native-community/cli-platform-ios": "2.0.0-rc.1", "abort-controller": "^3.0.0", "art": "^0.10.0", "base64-js": "^1.1.2", diff --git a/yarn.lock b/yarn.lock index b39d6f59e1a8d3..de6dbd857b043d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,16 +909,6 @@ dependencies: "@hapi/hoek" "6.x.x" -"@jest/console@^24.3.0": - version "24.3.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.3.0.tgz#7bd920d250988ba0bf1352c4493a48e1cb97671e" - integrity sha512-NaCty/OOei6rSDcbPdMiCbYCI0KGFGPgGO6B09lwWt5QTxnkuhKYET9El5u5z1GAcSxkQmSMtM63e24YabCWqA== - dependencies: - "@jest/source-map" "^24.3.0" - "@types/node" "*" - chalk "^2.0.1" - slash "^2.0.0" - "@jest/console@^24.7.1": version "24.7.1" resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545" @@ -971,16 +961,6 @@ "@jest/types" "^24.7.0" jest-mock "^24.7.0" -"@jest/fake-timers@^24.5.0": - version "24.5.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.5.0.tgz#4a29678b91fd0876144a58f8d46e6c62de0266f0" - integrity sha512-i59KVt3QBz9d+4Qr4QxsKgsIg+NjfuCjSOWj3RQhjF5JNy+eVJDhANQ4WzulzNCHd72srMAykwtRn5NYDGVraw== - dependencies: - "@jest/types" "^24.5.0" - "@types/node" "*" - jest-message-util "^24.5.0" - jest-mock "^24.5.0" - "@jest/fake-timers@^24.7.1": version "24.7.1" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.7.1.tgz#56e5d09bdec09ee81050eaff2794b26c71d19db2" @@ -1025,15 +1005,6 @@ graceful-fs "^4.1.15" source-map "^0.6.0" -"@jest/test-result@^24.5.0": - version "24.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.5.0.tgz#ab66fb7741a04af3363443084e72ea84861a53f2" - integrity sha512-u66j2vBfa8Bli1+o3rCaVnVYa9O8CAFZeqiqLVhnarXtreSXG33YQ6vNYBogT7+nYiFNOohTU21BKiHlgmxD5A== - dependencies: - "@jest/console" "^24.3.0" - "@jest/types" "^24.5.0" - "@types/istanbul-lib-coverage" "^1.1.0" - "@jest/test-result@^24.7.1": version "24.7.1" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.7.1.tgz#19eacdb29a114300aed24db651e5d975f08b6bbe" @@ -1074,14 +1045,6 @@ source-map "^0.6.1" write-file-atomic "2.4.1" -"@jest/types@^24.5.0": - version "24.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.5.0.tgz#feee214a4d0167b0ca447284e95a57aa10b3ee95" - integrity sha512-kN7RFzNMf2R8UDadPOl6ReyI+MT8xfqRuAnuVL+i4gwjv/zubdDK+EDeLHYwq1j0CSSR2W/MmgaRlMZJzXdmVA== - dependencies: - "@types/istanbul-lib-coverage" "^1.1.0" - "@types/yargs" "^12.0.9" - "@jest/types@^24.7.0": version "24.7.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.7.0.tgz#c4ec8d1828cdf23234d9b4ee31f5482a3f04f48b" @@ -1090,44 +1053,44 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" -"@react-native-community/cli-platform-android@2.0.0-rc.0", "@react-native-community/cli-platform-android@^2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-rc.0.tgz#8fcc57a68b3f971d322034c21ba09c580ce5455a" - integrity sha512-i9xCMx1AFTscFlEsUJZVn5r6h7ndjvBUUTgLR/4oV639Bcwlci3OvKD1bV5fdp1/L9Mv14iuDo7y1Jv9ubRi5w== +"@react-native-community/cli-platform-android@2.0.0-rc.1", "@react-native-community/cli-platform-android@^2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-rc.1.tgz#9f14106104b20bd94d05a3ddad79859b566f8996" + integrity sha512-gH+ev65wxuO9KQxYTvpRh3PFCVvYwxJdZecFZDknnedIx49eVxro99svO/wcp1OLdtzxV+ErFolpIFn0gSyVFg== dependencies: - "@react-native-community/cli-tools" "^2.0.0-rc.0" + "@react-native-community/cli-tools" "^2.0.0-rc.1" logkitty "^0.4.0" slash "^2.0.0" xmldoc "^0.4.0" -"@react-native-community/cli-platform-ios@2.0.0-rc.0", "@react-native-community/cli-platform-ios@^2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-rc.0.tgz#00489529d1715c80042a1649b0c6822aa7c785ba" - integrity sha512-v1BxVFHrrypI9XVtwtq0FPtZHusvCouPbpX7c4h4SiP66KT/+eAYVuOTpjSN+EMss/WZLeJKIPOiBn2ZohxcwA== +"@react-native-community/cli-platform-ios@2.0.0-rc.1", "@react-native-community/cli-platform-ios@^2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-rc.1.tgz#832c8c873193b8829249227fa1d1f734e7aa267e" + integrity sha512-okioIW81pd5vA1tgdSo8nYGnljqhaV91zprrkko6IhMV4sr/eGlN0D/cyFhUXmnBj6q63+X4Ulr809wqXjJ14w== dependencies: - "@react-native-community/cli-tools" "^2.0.0-rc.0" + "@react-native-community/cli-tools" "^2.0.0-rc.1" chalk "^1.1.1" xcode "^2.0.0" -"@react-native-community/cli-tools@^2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-rc.0.tgz#82eedb621921b4511a0a98dbc98eedc12bd98b9b" - integrity sha512-svdIsrcd905lberrY7jVMrHsoCy5PkVgJeiloMFjV6nPTPaKF7ujw2ftdUp9P66KRb7y/IMT5/4EDtntr8SkGg== +"@react-native-community/cli-tools@^2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-rc.1.tgz#a8c3f76e0c33ab689c1c769cbbed83add5c13b11" + integrity sha512-ZUc5s/aGdg7d3dT9eMAzKqWd5Lsa42TrsUWjcqaG7WTYUPIUHTWOcpnRLV4B5MUfmEEt3mboOoQZRUcDltz8kA== dependencies: chalk "^1.1.1" lodash "^4.17.5" mime "^2.4.1" node-fetch "^2.5.0" -"@react-native-community/cli@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-rc.0.tgz#fcc7551e93bc5fad456d26396de3b91b20ae7190" - integrity sha512-juHl7U3DSYjTexWmTiN54YSK52dM2nz0P2sJipZkJLbYSsSJTtvLiRWIKzaG/1Q03EfPp3DbkYTOXQMEERzQEg== +"@react-native-community/cli@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-rc.1.tgz#05766235131d4940315ae423848f61b302f4192a" + integrity sha512-mbU45L511eem67vRynHizKDpDv+Xm4xMwMV9HRbTspFxQyhxQd+A4zyQEWKho+/cXZbVhIh8myc/naQDZkmUxQ== dependencies: "@hapi/joi" "^15.0.3" - "@react-native-community/cli-platform-android" "^2.0.0-rc.0" - "@react-native-community/cli-platform-ios" "^2.0.0-rc.0" - "@react-native-community/cli-tools" "^2.0.0-rc.0" + "@react-native-community/cli-platform-android" "^2.0.0-rc.1" + "@react-native-community/cli-platform-ios" "^2.0.0-rc.1" + "@react-native-community/cli-tools" "^2.0.0-rc.1" chalk "^1.1.1" command-exists "^1.2.8" commander "^2.19.0" @@ -1143,10 +1106,10 @@ graceful-fs "^4.1.3" inquirer "^3.0.6" lodash "^4.17.5" - metro "^0.53.1" - metro-config "^0.53.1" - metro-core "^0.53.1" - metro-react-native-babel-transformer "^0.53.1" + metro "^0.54.1" + metro-config "^0.54.1" + metro-core "^0.54.1" + metro-react-native-babel-transformer "^0.54.1" minimist "^1.2.0" mkdirp "^0.5.1" morgan "^1.9.0" @@ -1201,21 +1164,11 @@ dependencies: "@babel/types" "^7.3.0" -"@types/istanbul-lib-coverage@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz#2cc2ca41051498382b43157c8227fea60363f94a" - integrity sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ== - "@types/istanbul-lib-coverage@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz#1eb8c033e98cf4e1a4cedcaf8bcafe8cb7591e85" integrity sha512-eAtOAFZefEnfJiRFQBGw1eYqa5GTLCZ1y86N0XSI/D6EB+E8z6VPV/UL7Gi5UEclFqoQk+6NRqEDsfmDLXn8sg== -"@types/node@*": - version "11.11.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.2.tgz#873d2c3f3824212cc16130074699e1bcb38c0231" - integrity sha512-iEaHiDNkHv4Jrm9O5T37OYEUwjJesiyt6ZlhLFK0sbo4CLD0jyCOB4Pc2F9iD3MbW2397SLNxZKdDGntGaBjQQ== - "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -2898,13 +2851,6 @@ exception-formatter@^1.0.4: dependencies: colors "^1.0.3" -exec-sh@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== - dependencies: - merge "^1.2.0" - exec-sh@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" @@ -3290,14 +3236,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== - dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" - fsevents@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" @@ -4083,20 +4021,6 @@ jest-get-type@^24.3.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.3.0.tgz#582cfd1a4f91b5cdad1d43d2932f816d543c65da" integrity sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow== -jest-haste-map@24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.0.0.tgz#e9ef51b2c9257384b4d6beb83bd48c65b37b5e6e" - integrity sha512-CcViJyUo41IQqttLxXVdI41YErkzBKbE6cS6dRAploCeutePYfUimWd3C9rQEWhX0YBOQzvNsC0O9nYxK2nnxQ== - dependencies: - fb-watchman "^2.0.0" - graceful-fs "^4.1.15" - invariant "^2.2.4" - jest-serializer "^24.0.0" - jest-util "^24.0.0" - jest-worker "^24.0.0" - micromatch "^3.1.10" - sane "^3.0.0" - jest-haste-map@^24.7.1: version "24.7.1" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.7.1.tgz#772e215cd84080d4bbcb759cfb668ad649a21471" @@ -4165,20 +4089,6 @@ jest-matcher-utils@^24.7.0: jest-get-type "^24.3.0" pretty-format "^24.7.0" -jest-message-util@^24.5.0: - version "24.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.5.0.tgz#181420a65a7ef2e8b5c2f8e14882c453c6d41d07" - integrity sha512-6ZYgdOojowCGiV0D8WdgctZEAe+EcFU+KrVds+0ZjvpZurUW2/oKJGltJ6FWY2joZwYXN5VL36GPV6pNVRqRnQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/test-result" "^24.5.0" - "@jest/types" "^24.5.0" - "@types/stack-utils" "^1.0.1" - chalk "^2.0.1" - micromatch "^3.1.10" - slash "^2.0.0" - stack-utils "^1.0.1" - jest-message-util@^24.7.1: version "24.7.1" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.7.1.tgz#f1dc3a6c195647096a99d0f1dadbc447ae547018" @@ -4193,13 +4103,6 @@ jest-message-util@^24.7.1: slash "^2.0.0" stack-utils "^1.0.1" -jest-mock@^24.5.0: - version "24.5.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.5.0.tgz#976912c99a93f2a1c67497a9414aa4d9da4c7b76" - integrity sha512-ZnAtkWrKf48eERgAOiUxVoFavVBziO2pAi2MfZ1+bGXVkDfxWLxU0//oJBkgwbsv6OAmuLBz4XFFqvCFMqnGUw== - dependencies: - "@jest/types" "^24.5.0" - jest-mock@^24.7.0: version "24.7.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.7.0.tgz#e49ce7262c12d7f5897b0d8af77f6db8e538023b" @@ -4291,12 +4194,7 @@ jest-runtime@^24.7.1: strip-bom "^3.0.0" yargs "^12.0.2" -jest-serializer@24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.0.0.tgz#522c44a332cdd194d8c0531eb06a1ee5afb4256b" - integrity sha512-9FKxQyrFgHtx3ozU+1a8v938ILBE7S8Ko3uiAVjT8Yfi2o91j/fj81jacCQZ/Ihjiff/VsUCXVgQ+iF1XdImOw== - -jest-serializer@^24.0.0, jest-serializer@^24.4.0: +jest-serializer@^24.4.0: version "24.4.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.4.0.tgz#f70c5918c8ea9235ccb1276d232e459080588db3" integrity sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q== @@ -4319,25 +4217,6 @@ jest-snapshot@^24.7.1: pretty-format "^24.7.0" semver "^5.5.0" -jest-util@^24.0.0: - version "24.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.5.0.tgz#9d9cb06d9dcccc8e7cc76df91b1635025d7baa84" - integrity sha512-Xy8JsD0jvBz85K7VsTIQDuY44s+hYJyppAhcsHsOsGisVtdhar6fajf2UOf2mEVEgh15ZSdA0zkCuheN8cbr1Q== - dependencies: - "@jest/console" "^24.3.0" - "@jest/fake-timers" "^24.5.0" - "@jest/source-map" "^24.3.0" - "@jest/test-result" "^24.5.0" - "@jest/types" "^24.5.0" - "@types/node" "*" - callsites "^3.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.15" - is-ci "^2.0.0" - mkdirp "^0.5.1" - slash "^2.0.0" - source-map "^0.6.0" - jest-util@^24.7.1: version "24.7.1" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.7.1.tgz#b4043df57b32a23be27c75a2763d8faf242038ff" @@ -4392,23 +4271,6 @@ jest-watcher@^24.7.1: jest-util "^24.7.1" string-length "^2.0.0" -jest-worker@24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d" - integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg== - dependencies: - merge-stream "^1.0.1" - supports-color "^6.1.0" - -jest-worker@^24.0.0: - version "24.4.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.4.0.tgz#fbc452b0120bb5c2a70cdc88fa132b48eeb11dd0" - integrity sha512-BH9X/klG9vxwoO99ZBUbZFfV8qO0XNZ5SIiCyYK2zOuJBl6YJVAeNIQjcoOVNu4HGEHeYEKsUWws8kSlSbZ9YQ== - dependencies: - "@types/node" "*" - merge-stream "^1.0.1" - supports-color "^6.1.0" - jest-worker@^24.6.0: version "24.6.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3" @@ -4845,29 +4707,6 @@ merge-stream@^1.0.1: dependencies: readable-stream "^2.0.1" -merge@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" - integrity sha1-dTHjnUlJwoGma4xabgJl6LBYlNo= - -metro-babel-register@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.53.1.tgz#41c73313ff882d28d8f7df072d2c7a6b7b314ac8" - integrity sha512-kDu7mktGCVdpa2islDzmNXZ0sGQjUvIEcQkmO9pt4b4d8QVecEHyHSZB9jvWnE2w9lADzvnERmZLHS2iDDYOyw== - dependencies: - "@babel/core" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/register" "^7.0.0" - core-js "^2.2.2" - escape-string-regexp "^1.0.5" - metro-babel-register@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.54.1.tgz#7d2bfe444b1ccef8de99aedc7d9330891d806076" @@ -4886,13 +4725,6 @@ metro-babel-register@0.54.1: core-js "^2.2.2" escape-string-regexp "^1.0.5" -metro-babel-transformer@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.53.1.tgz#a076fd77a9a7aef8004706edf537dcd1fec4a79e" - integrity sha512-cgZj9KK/SLxsO/rAmrlnZpaBlLhxuWxGrQkkiWxV/OjfbW8nvodozfZ3Euxvh4Ytf0e8qgTFG3JpQf8EGSDp7w== - dependencies: - "@babel/core" "^7.0.0" - metro-babel-transformer@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.54.1.tgz#371ffa2d1118b22cc9e40b3c3ea6738c49dae9dc" @@ -4900,13 +4732,6 @@ metro-babel-transformer@0.54.1: dependencies: "@babel/core" "^7.0.0" -metro-babel7-plugin-react-transform@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-babel7-plugin-react-transform/-/metro-babel7-plugin-react-transform-0.53.1.tgz#9ad31e5c84f5003333a6a3cf79f2d093cd3b2ddc" - integrity sha512-98lEpTu7mox/7QurxVuLnbjrGDdayjpS2Z1T4vkLcP+mBxzloKJuTRnmtyWC8cNlx9qjimHGDlqtNY78rQ8rsA== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - metro-babel7-plugin-react-transform@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-babel7-plugin-react-transform/-/metro-babel7-plugin-react-transform-0.54.1.tgz#5335b810284789724886dc483d5bde9c149a1996" @@ -4914,97 +4739,56 @@ metro-babel7-plugin-react-transform@0.54.1: dependencies: "@babel/helper-module-imports" "^7.0.0" -metro-cache@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.53.1.tgz#38d73c441771bdd2437a55d50943e346e1897108" - integrity sha512-27Cbo32nabef/P+y5s3cpaIUWa7Hpql2xD0HqQD8AbCfSG4xraEoBOLCmvB6wusvDAnQAcuglLq9AUbTvcSebA== +metro-cache@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.54.1.tgz#2e9017cbd11106837b8c385c9eb8c8175469a8c1" + integrity sha512-RxCFoNcANHXZYi4MIQNnqh68gUnC3bMpzCFJY5pBoqqdrkkn8ibYglBweA0/DW7hx1OZTJWelwS1Dp8xxmE2CA== dependencies: - jest-serializer "24.0.0" - metro-core "0.53.1" + jest-serializer "^24.4.0" + metro-core "0.54.1" mkdirp "^0.5.1" rimraf "^2.5.4" -metro-config@0.53.1, metro-config@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.53.1.tgz#a522beec446187b010c0e68273015818d1c6dfb9" - integrity sha512-3hRweWmrGs8NOjQXLsg/FHAEWqCnfNKLXM4BcI8RXQFvrQQRqhoXCuhcTfM9lSfNkefJiRp+4wW6cHXgo/TP6w== +metro-config@0.54.1, metro-config@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.54.1.tgz#808b4e17625d9f4e9afa34232778fdf8e63cc8dd" + integrity sha512-FpxrA+63rGkPGvGI653dvuSreJzU+eOTILItVnnhmqwn2SAK5V00N/qGTOIJe2YIuWEFXwCzw9lXmANrXbwuGg== dependencies: cosmiconfig "^5.0.5" - metro "0.53.1" - metro-cache "0.53.1" - metro-core "0.53.1" - pretty-format "24.0.0-alpha.6" + jest-validate "^24.7.0" + metro "0.54.1" + metro-cache "0.54.1" + metro-core "0.54.1" + pretty-format "^24.7.0" -metro-core@0.53.1, metro-core@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.53.1.tgz#350211c6327ccf307270199bb1c04012ec2d7d96" - integrity sha512-bBK0GMZWsZrdBGi+jh/87g0VvItT2jez6aj+vRw8AcBataT81SZ5WsSAw3CtbivBXXR7x3oK49T6ZZ+D79VZAw== +metro-core@0.54.1, metro-core@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.54.1.tgz#17f6ecc167918da8819d4af5726349e55714954b" + integrity sha512-8oz3Ck7QFBzW9dG9tKFhrXHKPu2Ajx3R7eatf61Gl6Jf/tF7PNouv3wHxPsJW3oXDFiwKLszd89+OgleTGkB5g== dependencies: - jest-haste-map "24.0.0" + jest-haste-map "^24.7.1" lodash.throttle "^4.1.1" - metro-resolver "0.53.1" + metro-resolver "0.54.1" wordwrap "^1.0.0" -metro-inspector-proxy@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.53.1.tgz#cff4b9fa8b9e5598c034469bd30ef07093f75b28" - integrity sha512-4q5WIFFmpjtKbY2vze3tNI3hPUFrvv1iwTrpz3DMdQ+NYZO6aEwCxtgZAt8N4HC3xZMdECL+DDKKAJu+4jsiEA== +metro-inspector-proxy@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.54.1.tgz#0ef48ee3feb11c6da47aa100151a9bf2a7c358ee" + integrity sha512-sf6kNu7PgFW6U+hU7YGZfbAUKAPVvCJhY8YVu/A1RMKH9nNULrCo+jlWh0gWgmFfWRQiAPCElevROg+5somk8A== dependencies: - chalk "^2.4.1" connect "^3.6.5" + debug "^2.2.0" rxjs "^5.4.3" ws "^1.1.5" yargs "^9.0.0" -metro-minify-uglify@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.53.1.tgz#145b6e37c09e3ff8fb1bbd3221e5a3fded044904" - integrity sha512-uTdsoACy0WP51qDNrKcLILcpZOMLGyi2B9j3pu9zVRts7hlfVQGxBg4v3uDZ+L7zJ7TKR15p4iMXFmTAkRBpdA== +metro-minify-uglify@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.54.1.tgz#54ed1cb349245ce82dba8cc662bbf69fbca142c3" + integrity sha512-z+pOPna/8IxD4OhjW6Xo1mV2EszgqqQHqBm1FdmtdF6IpWkQp33qpDBNEi9NGZTOr7pp2bvcxZnvNJdC2lrK9Q== dependencies: uglify-es "^3.1.9" -metro-react-native-babel-preset@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.53.1.tgz#6cd9e41a1b9a6e210e71ef2adf114219b4eaf2ec" - integrity sha512-Uf8EGL8kIPhDkoSdAAysNPxPQclUS2R1QC4cwnc8bkk2f6yqGn+1CorfiY9AaqlLEth5mKQqdtRYFDTFfB9QyA== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.0.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.2.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-assign" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-regenerator" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.0.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - metro-babel7-plugin-react-transform "0.53.1" - react-transform-hmr "^1.0.4" - metro-react-native-babel-preset@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.54.1.tgz#b8f03865c381841d7f8912e7ba46804ea3a928b8" @@ -5047,7 +4831,7 @@ metro-react-native-babel-preset@0.54.1: metro-babel7-plugin-react-transform "0.54.1" react-transform-hmr "^1.0.4" -metro-react-native-babel-transformer@0.54.1: +metro-react-native-babel-transformer@0.54.1, metro-react-native-babel-transformer@^0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.54.1.tgz#45b56db004421134e10e739f69e8de50775fef17" integrity sha512-ECw7xG91t8dk/PHdiyoC5SP1s9OQzfmJzG5m0YOZaKtHMe534qTDbncxaKfTI3CP99yti2maXFBRVj+xyvph/g== @@ -5057,34 +4841,26 @@ metro-react-native-babel-transformer@0.54.1: metro-babel-transformer "0.54.1" metro-react-native-babel-preset "0.54.1" -metro-react-native-babel-transformer@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.53.1.tgz#addf31b3a9b5fc512b9ff6967d923dcfcda56394" - integrity sha512-UB64jN/akuTdDmoQlw+yLBifJhQzJr7QPP3cwitwM5XD4d9M+12pZreeFn66oMakTy4pNx4jkaYEJ5rLyh/b0Q== - dependencies: - "@babel/core" "^7.0.0" - babel-preset-fbjs "^3.1.2" - metro-babel-transformer "0.53.1" - metro-react-native-babel-preset "0.53.1" - -metro-resolver@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.53.1.tgz#e21df30c0b9913c7cbeeda9c28d8ffe0ae58cd53" - integrity sha512-UOL2AY3HF3kyuwO+SXceA7MvVbxGZTwRmWOcRl2mYMZ66osSygFgR0WoYFAlxoW83c1ZDYXMIg78ob8bs0lSAg== +metro-resolver@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.54.1.tgz#0295b38624b678b88b16bf11d47288845132b087" + integrity sha512-Byv1LIawYAASy9CFRwzrncYnqaFGLe8vpw178EtzStqP05Hu6hXSqkNTrfoXa+3V9bPFGCrVzFx2NY3gFp2btg== dependencies: absolute-path "^0.0.0" -metro-source-map@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.53.1.tgz#61d915720eb90722d55252f3bd014ba0ce8fabfd" - integrity sha512-mZ8NJMq5lKE9+0gfhpYFVqK3z4wng6xCzOMXoROjkOsO/exbHGK4oSfOzEnVl6oCRBTGMfaeB32ZeECwZ9O0jw== +metro-source-map@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.54.1.tgz#e17bad53c11978197d3c05c9168d799c2e04dcc5" + integrity sha512-E9iSYMSUSq5qYi1R2hTQtxH4Mxjzfgr/jaSmQIWi7h3fG2P1qOZNNSzeaeUeTK+s2N/ksVlkcL5kMikol8CDrQ== dependencies: + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" source-map "^0.5.6" -metro@0.53.1, metro@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.53.1.tgz#23fb558eb22e8de8d84fa3f456adfdedec435021" - integrity sha512-Q2iVHfUu5NO2o0dZukBkWrW5s2LiResQuK5KalomNsOHLguOYI5r1nR5QdznZ05GI96iR0fgNvFWfPMyIhtKvw== +metro@0.54.1, metro@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.54.1.tgz#a629be00abee5a450a25a8f71c24745f70cc9b44" + integrity sha512-6ODPT4mEo4FCpbExRNnQAcZmf1VeNvYOTMj2Na03FjGqhNODHhI2U/wF/Ul5gqTyJ2dVdkXeyvKW3gl/LrnJRg== dependencies: "@babel/core" "^7.0.0" "@babel/generator" "^7.0.0" @@ -5108,21 +4884,21 @@ metro@0.53.1, metro@^0.53.1: graceful-fs "^4.1.3" image-size "^0.6.0" invariant "^2.2.4" - jest-haste-map "24.0.0" - jest-worker "24.0.0" + jest-haste-map "^24.7.1" + jest-worker "^24.6.0" json-stable-stringify "^1.0.1" lodash.throttle "^4.1.1" merge-stream "^1.0.1" - metro-babel-register "0.53.1" - metro-babel-transformer "0.53.1" - metro-cache "0.53.1" - metro-config "0.53.1" - metro-core "0.53.1" - metro-inspector-proxy "0.53.1" - metro-minify-uglify "0.53.1" - metro-react-native-babel-preset "0.53.1" - metro-resolver "0.53.1" - metro-source-map "0.53.1" + metro-babel-register "0.54.1" + metro-babel-transformer "0.54.1" + metro-cache "0.54.1" + metro-config "0.54.1" + metro-core "0.54.1" + metro-inspector-proxy "0.54.1" + metro-minify-uglify "0.54.1" + metro-react-native-babel-preset "0.54.1" + metro-resolver "0.54.1" + metro-source-map "0.54.1" mime-types "2.1.11" mkdirp "^0.5.1" node-fetch "^2.2.0" @@ -5901,14 +5677,6 @@ prettier@1.17.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.0.tgz#53b303676eed22cc14a9f0cec09b477b3026c008" integrity sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw== -pretty-format@24.0.0-alpha.6: - version "24.0.0-alpha.6" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0-alpha.6.tgz#25ad2fa46b342d6278bf241c5d2114d4376fbac1" - integrity sha512-zG2m6YJeuzwBFqb5EIdmwYVf30sap+iMRuYNPytOccEXZMAJbPIFGKVJ/U0WjQegmnQbRo9CI7j6j3HtDaifiA== - dependencies: - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - pretty-format@^24.0.0: version "24.0.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0.tgz#cb6599fd73ac088e37ed682f61291e4678f48591" @@ -6461,23 +6229,6 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sane@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" - integrity sha512-G5GClRRxT1cELXfdAq7UKtUsv8q/ZC5k8lQGmjEm4HcAl3HzBy68iglyNCmw4+0tiXPCBZntslHlRhbnsSws+Q== - dependencies: - anymatch "^2.0.0" - capture-exit "^1.2.0" - exec-sh "^0.2.0" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - watch "~0.18.0" - optionalDependencies: - fsevents "^1.2.3" - sane@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/sane/-/sane-4.0.3.tgz#e878c3f19e25cc57fbb734602f48f8a97818b181" @@ -7329,14 +7080,6 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -watch@~0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" - integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= - dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" - wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" From 1f3e4df6a7d42d8a6060d1a21949159a7a90d826 Mon Sep 17 00:00:00 2001 From: Aditya Sharat Date: Mon, 10 Jun 2019 06:52:54 -0700 Subject: [PATCH 156/330] Back out "[litho] Adds check to unset a YogaNode's parent during reconciliation." Summary: Removes `unsetOwner` from Yoga. This was temporarily for patching a crash. Reviewed By: colriot Differential Revision: D15737613 fbshipit-source-id: 8ab93ecf7ffb913df6207fe5db47a8cc93eded2c --- ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java | 2 -- .../src/main/java/com/facebook/yoga/YogaNodeJNIBase.java | 5 ----- 2 files changed, 7 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 9a8e19663fd1a0..a01a0bdde49ddb 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -42,8 +42,6 @@ public static YogaNode create(YogaConfig config) { @Nullable public abstract YogaNode getOwner(); - public abstract void unsetOwner(); - /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java index 0e1f68c8e97a35..c48162f4a470d6 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -137,11 +137,6 @@ public YogaNodeJNIBase getOwner() { return mOwner; } - @Override - public void unsetOwner() { - mOwner = null; - } - /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable From 608cf6fe09c9beea394654bb2f5759c7e0c80c06 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 10 Jun 2019 10:48:12 -0700 Subject: [PATCH 157/330] Make CompositeReactPackage support TurboReactPackage Summary: ## Description CompositeReactPackage will now eagerly initialize all NativeModules inside the TurboReactPackages. Before it would just crash the program because calling `createNativeModules()` on the TurboReactPackage instance. Longer term, we should make CompositeReactPackage a TurboReactPackage. ## Why am I making this change? I made MainReactPackage into a TurboReactPackge. But ExpressWifiTechnician uses MainReactPackage to create a CompositeReactPackage: **java/com/expresswifi/technician/MainActivity.java** ``` protected ReactPackage getPackage() { ReactInstanceManager reactInstanceManager = getReactInstanceManager(); Nullable DevSupportManager devSupportManager = null; if (reactInstanceManager != null) { devSupportManager = reactInstanceManager.getDevSupportManager(); } return new CompositeReactPackage( super.getPackage(), mXWFTechnicianReactPackage, new RNFusedLocationPackage(), mXWFTechnicialMobileConfigPackageProvider.get(devSupportManager)); } ``` **java/com/facebook/catalyst/shell/MainReactActivity.java** ``` public abstract class MainReactActivity extends AbstractReactActivity { protected ReactPackage getPackage() { return new MainReactPackage(); } } ``` Reviewed By: fkgozali Differential Revision: D15738677 fbshipit-source-id: 3220dfe6434de56f2917c77fb21acef4cfc79278 --- .../facebook/react/CompositeReactPackage.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java index d6c13684e01bc1..9450719098ec32 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java @@ -8,6 +8,8 @@ import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; @@ -18,6 +20,7 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nullable; +import com.facebook.react.TurboReactPackage; /** * {@code CompositeReactPackage} allows to create a single package composed of views and modules @@ -46,6 +49,25 @@ public List createNativeModules(ReactApplicationContext reactConte // This is for backward compatibility. final Map moduleMap = new HashMap<>(); for (ReactPackage reactPackage : mChildReactPackages) { + /** + * For now, we eagerly initialize the NativeModules inside TurboReactPackages. + * Ultimately, we should turn CompositeReactPackage into a TurboReactPackage + * and remove this eager initialization. + * + * TODO: T45627020 + */ + if (reactPackage instanceof TurboReactPackage) { + TurboReactPackage turboReactPackage = (TurboReactPackage)reactPackage; + ReactModuleInfoProvider moduleInfoProvider = turboReactPackage.getReactModuleInfoProvider(); + Map moduleInfos = moduleInfoProvider.getReactModuleInfos(); + + for (final String moduleName : moduleInfos.keySet()) { + moduleMap.put(moduleName, turboReactPackage.getModule(moduleName, reactContext)); + } + + continue; + } + for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) { moduleMap.put(nativeModule.getName(), nativeModule); } From 72be568666e58f703684ebeb2ad1a135826d8c6f Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 10 Jun 2019 10:53:29 -0700 Subject: [PATCH 158/330] Reland "[RN][TurboModule] Enable TurboModules for FB4A" Summary: These changes were originally landed in D15327683. Unfortunately, I had to back these out because they revelaled problems with our TurboModules infra. Those problems have since been fixed, so I think it's safe for us to re-land these changes. Please refer to D15327683 for a description. Differential Revision: D15739355 fbshipit-source-id: 69bb3cec0731ba325f60c6c8459426546c79b54d --- .../main/java/com/facebook/react/bridge/BaseJavaModule.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index 04ca7a91c74969..da1d60f94f0897 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -67,4 +67,9 @@ public void onCatalystInstanceDestroy() { public boolean hasConstants() { return false; } + + // Cleanup Logic for TurboModuels + public void invalidate() { + // Do nothing + } } From 20102ef5b149f322347d87e4c310036704ef1a50 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 12:00:52 -0700 Subject: [PATCH 159/330] Check TurboModules first in TurboModuleRegistry Summary: Reverse the order in which we look for modules in TurboModuleRegistry to check TurboModules first, and then fall back to legacy native modules. The main motivation for this is Venice, since requiring NativeModules.js fatals because there's no batched bridge. But we'll probably want to do this eventually anyway. I ran a mobilelab for Marketplace home and am not seeing any significant difference in TTI. Reviewed By: fkgozali Differential Revision: D15703655 fbshipit-source-id: d65a4d7e09077474c30fb3938e38aee63bfa4eca --- Libraries/TurboModule/TurboModuleRegistry.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Libraries/TurboModule/TurboModuleRegistry.js b/Libraries/TurboModule/TurboModuleRegistry.js index d0e0cd0176c33a..03d84d6dd7541f 100644 --- a/Libraries/TurboModule/TurboModuleRegistry.js +++ b/Libraries/TurboModule/TurboModuleRegistry.js @@ -17,17 +17,19 @@ import invariant from 'invariant'; const turboModuleProxy = global.__turboModuleProxy; export function get(name: string): ?T { + if (turboModuleProxy != null) { + const module: ?T = turboModuleProxy(name); + if (module != null) { + return module; + } + } + // Backward compatibility layer during migration. const legacyModule = NativeModules[name]; if (legacyModule != null) { return ((legacyModule: any): T); } - if (turboModuleProxy != null) { - const module: ?T = turboModuleProxy(name); - return module; - } - return null; } From bbeace1342e078bcf250f776f6de4e432c9c6bd3 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Mon, 10 Jun 2019 12:19:14 -0700 Subject: [PATCH 160/330] Remove `React.js` from RN open source Summary: This diff removes the `React.js` forwarding module from RN open source which was only used for haste requires. I moved this file to FB internal and manually changed requires from `React` to `react`. However, I can't fully remove this forwarding module because we have files shared from www that expect to require React via the capitalized named. Reviewed By: yungsters Differential Revision: D15738887 fbshipit-source-id: b5b6c0be258582cfad92c13d174e5490c75152d9 --- Libraries/react-native/React.js | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 Libraries/react-native/React.js diff --git a/Libraries/react-native/React.js b/Libraries/react-native/React.js deleted file mode 100644 index ac9f5d1bcec4a7..00000000000000 --- a/Libraries/react-native/React.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -module.exports = require('react'); From 5c399a9f74f22c58c11f75abde32ac7dc269ccc0 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 13:50:58 -0700 Subject: [PATCH 161/330] Workaround to avoid bridge access from ReactTextView for Venice Summary: D14014668 introduced support for nesting views within Text on Android. Part of the implementation involved accessing the UIManagerModule from ReactTextView through context. This doesn't work in bridgeless RN because we have no UIManagerModule, and the ReactContext has no Catalyst instance. Trying to access the Catalyst instance from ReactContext throws an exception if it doesn't exist, so i'm just adding a simple check here to make sure the instance exists before proceeding. This means that this feature won't work in bridgeless mode, but that's ok for now - eventually we want to change the way this works so that it doesn't rely on accessing views in Java, which is potentially unsafe (there's nothing to stop you from mutating the views, and cpp/js would never know about it). Reviewed By: mdvacca Differential Revision: D15703100 fbshipit-source-id: 0448d55b8345fc707a25210a505cb6ac520c708a --- .../java/com/facebook/react/views/text/ReactTextView.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java index b14e49e8bf9afd..feede92d6e83b3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java @@ -114,6 +114,12 @@ protected void onLayout(boolean changed, return; } + if (!getReactContext().hasCatalystInstance()) { + // In bridgeless mode there's no Catalyst instance; in that case, bail. + // TODO (T45503888): Figure out how to support nested views from JS or cpp. + return; + } + UIManagerModule uiManager = getReactContext().getNativeModule(UIManagerModule.class); Spanned text = (Spanned) getText(); From 4e7155ee5338e0a48ab8dd1380d7fa64d70d7a1d Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 14:59:21 -0700 Subject: [PATCH 162/330] Add RN$Bridgeless flag, use it to conditionally skip bridge setup Summary: In bridgeless mode we don't want to set up the batched bridge, which is set up as part of InitializeCore. Instead of deleting InitializeCore completely, let's just skip this step if we're in bridgeless mode, which we'll detect using a global variable set on the runtime from cpp (`RN$Bridgeless`). This way you still get an error if the bridge is somehow not set up properly when you're not in bridgeless mode (it won't fail silently). Reviewed By: fkgozali Differential Revision: D15721940 fbshipit-source-id: 73896e25874dd000f37d1abc9cf6be549ab3434f --- Libraries/Core/setUpBatchedBridge.js | 78 +++++++++++++++------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/Libraries/Core/setUpBatchedBridge.js b/Libraries/Core/setUpBatchedBridge.js index e9d33fe6ae3a25..21c85c690312d6 100644 --- a/Libraries/Core/setUpBatchedBridge.js +++ b/Libraries/Core/setUpBatchedBridge.js @@ -10,42 +10,48 @@ 'use strict'; /** - * Set up the BatchedBridge. This must be done after the other steps in - * InitializeCore to ensure that the JS environment has been initialized. - * You can use this module directly, or just require InitializeCore. + * We don't set up the batched bridge in bridgeless mode. Once we've migrated + * everything over to bridgeless we can just delete this file. */ -const BatchedBridge = require('../BatchedBridge/BatchedBridge'); -BatchedBridge.registerLazyCallableModule('Systrace', () => - require('../Performance/Systrace'), -); -BatchedBridge.registerLazyCallableModule('JSTimers', () => - require('./Timers/JSTimers'), -); -BatchedBridge.registerLazyCallableModule('HeapCapture', () => - require('../HeapCapture/HeapCapture'), -); -BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => - require('../Performance/SamplingProfiler'), -); -BatchedBridge.registerLazyCallableModule('RCTLog', () => - require('../Utilities/RCTLog'), -); -BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => - require('../EventEmitter/RCTDeviceEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => - require('../EventEmitter/RCTNativeAppEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('GlobalPerformanceLogger', () => - require('../Utilities/GlobalPerformanceLogger'), -); -BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => - require('../Utilities/JSDevSupportModule'), -); - -if (__DEV__ && !global.__RCTProfileIsProfiling) { - BatchedBridge.registerCallableModule( - 'HMRClient', - require('../Utilities/HMRClient'), +if (!global.RN$Bridgeless) { + /** + * Set up the BatchedBridge. This must be done after the other steps in + * InitializeCore to ensure that the JS environment has been initialized. + * You can use this module directly, or just require InitializeCore. + */ + const BatchedBridge = require('../BatchedBridge/BatchedBridge'); + BatchedBridge.registerLazyCallableModule('Systrace', () => + require('../Performance/Systrace'), + ); + BatchedBridge.registerLazyCallableModule('JSTimers', () => + require('./Timers/JSTimers'), + ); + BatchedBridge.registerLazyCallableModule('HeapCapture', () => + require('../HeapCapture/HeapCapture'), + ); + BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => + require('../Performance/SamplingProfiler'), + ); + BatchedBridge.registerLazyCallableModule('RCTLog', () => + require('../Utilities/RCTLog'), ); + BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => + require('../EventEmitter/RCTDeviceEventEmitter'), + ); + BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => + require('../EventEmitter/RCTNativeAppEventEmitter'), + ); + BatchedBridge.registerLazyCallableModule('GlobalPerformanceLogger', () => + require('../Utilities/GlobalPerformanceLogger'), + ); + BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => + require('../Utilities/JSDevSupportModule'), + ); + + if (__DEV__ && !global.__RCTProfileIsProfiling) { + BatchedBridge.registerCallableModule( + 'HMRClient', + require('../Utilities/HMRClient'), + ); + } } From 422472e5d91ea2023ea121ebce6e02fa361c3905 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 14:59:21 -0700 Subject: [PATCH 163/330] Don't check native view configs in bridgeless mode Summary: `verifyComponentAttributeEquivalence` checks the new JS view configs against what we get from native at runtime (in dev only). This breaks in bridgeless mode because there is no paper UIManager to ask for the viewconfigs from; this diff uses the flag from D15721940 to skip this check. Reviewed By: fkgozali Differential Revision: D15722127 fbshipit-source-id: d9227107e0ff7814c34beaae6461bb8232699c94 --- Libraries/Utilities/verifyComponentAttributeEquivalence.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index 296b7837cbd7af..e64eb65d828905 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -42,7 +42,7 @@ function verifyComponentAttributeEquivalence( componentName: string, config: ReactNativeBaseComponentViewConfig<>, ) { - if (__DEV__) { + if (__DEV__ && !global.RN$Bridgeless) { const nativeAttributes = getNativeComponentAttributes(componentName); ['validAttributes', 'bubblingEventTypes', 'directEventTypes'].forEach( From 7225daf98d5b1cf71a90a491275077e454e7e4db Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 10 Jun 2019 18:37:57 -0700 Subject: [PATCH 164/330] TM iOS: Support @synthesize methodQueue auto queue creation Summary: Some native modules defined `synthesize methodQueue` which will ask the bridge to create a new serial queue for them. TM system needs to preserve this behavior for backward compatibility. In the future though, this magic shall be removed. Reviewed By: mdvacca Differential Revision: D15748198 fbshipit-source-id: 66a4b60a2769ac967a8d3bb00c4c635a68daebbc --- .../platform/ios/RCTTurboModuleManager.mm | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 91fdbc9b329efd..83da4c8b50b952 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -289,6 +289,30 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name } } + /** + * Some modules need their own queues, but don't provide any, so we need to create it for them. + * These modules typically have the following: + * `@synthesize methodQueue = _methodQueue` + */ + if ([module respondsToSelector:@selector(methodQueue)]) { + dispatch_queue_t methodQueue = [module performSelector:@selector(methodQueue)]; + if (!methodQueue) { + NSString *moduleClassName = NSStringFromClass(module.class); + NSString *queueName = [NSString stringWithFormat:@"com.facebook.react.%@Queue", moduleClassName]; + methodQueue = dispatch_queue_create(queueName.UTF8String, DISPATCH_QUEUE_SERIAL); + @try { + [(id)module setValue:methodQueue forKey:@"methodQueue"]; + } @catch (NSException *exception) { + RCTLogError( + @"TM: %@ is returning nil for its methodQueue, which is not " + "permitted. You must either return a pre-initialized " + "queue, or @synthesize the methodQueue to let the bridge " + "create a queue for you.", + moduleClassName); + } + } + } + /** * Broadcast that this TurboModule was created. * From c0bf53b7165ab6b48b853b3eebda9593f347fcdf Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 10 Jun 2019 18:37:57 -0700 Subject: [PATCH 165/330] TM iOS: attempt to convert number args using RCTConvert as well Summary: Some native modules methods expects number-based args like `NSDate`. For backward compatibility, the incoming numbers should be converted using RCTConvert, just like object args. Reviewed By: mdvacca Differential Revision: D15748968 fbshipit-source-id: 4db2cb0c41eda1bbe8cde7b0365d9c3d675f5fb5 --- .../core/platform/ios/RCTTurboModule.mm | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm index f2862d60d71cf9..ce6c7616788173 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm @@ -460,6 +460,29 @@ void cleanup() { */ if (objCArgType[0] == _C_ID) { id objCArg = [NSNumber numberWithDouble:v]; + NSString *methodNameNSString = @(methodName.c_str()); + + /** + * Convert numbers using RCTConvert if possible. + */ + NSString *argumentType = getArgumentTypeName(methodNameNSString, i); + if (argumentType != nil) { + NSString *rctConvertMethodName = [NSString stringWithFormat:@"%@:", argumentType]; + SEL rctConvertSelector = NSSelectorFromString(rctConvertMethodName); + + if ([RCTConvert respondsToSelector:rctConvertSelector]) { + // Message dispatch logic from old infra + id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; + id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg); + + [inv setArgument:(void *)&convertedObjCArg atIndex:i + 2]; + if (convertedObjCArg) { + [retainedObjectsForInvocation addObject:convertedObjCArg]; + } + continue; + } + } + [inv setArgument:(void *)&objCArg atIndex:i + 2]; [retainedObjectsForInvocation addObject:objCArg]; } else { @@ -486,7 +509,7 @@ void cleanup() { NSString *rctConvertMethodName = [NSString stringWithFormat:@"%@:", argumentType]; SEL rctConvertSelector = NSSelectorFromString(rctConvertMethodName); - if ([RCTConvert respondsToSelector: rctConvertSelector]) { + if ([RCTConvert respondsToSelector:rctConvertSelector]) { // Message dispatch logic from old infra id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg); From 66e02588850ee81aa8574edc46c954e7bccf42e7 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 10 Jun 2019 20:34:06 -0700 Subject: [PATCH 166/330] TM: attempt to integrate with internal codegen infra Summary: An attempt to integrate the module flow types with internal codegen infra. Nothing of interest here, other than minor tweak on a spec (we don't support tupples...). Reviewed By: mdvacca Differential Revision: D15753278 fbshipit-source-id: b91d564fdbe8f72b90bea725779a9684993472b5 --- Libraries/Alert/Alert.js | 18 +++++++++++++++++- Libraries/Alert/NativeAlertManager.js | 19 +------------------ Libraries/ReactNative/NativeUIManager.js | 2 +- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index c0afc6573bb73f..55bdce3fd40704 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -15,7 +15,23 @@ import NativeDialogManagerAndroid, { type DialogOptions, } from '../NativeModules/specs/NativeDialogManagerAndroid'; import RCTAlertManager from './RCTAlertManager'; -import {type Buttons, type Options, type AlertType} from './NativeAlertManager'; + +export type AlertType = + | 'default' + | 'plain-text' + | 'secure-text' + | 'login-password'; +export type AlertButtonStyle = 'default' | 'cancel' | 'destructive'; +export type Buttons = Array<{ + text?: string, + onPress?: ?Function, + style?: AlertButtonStyle, +}>; + +type Options = { + cancelable?: ?boolean, + onDismiss?: ?() => void, +}; /** * Launches an alert dialog with the specified title and message. diff --git a/Libraries/Alert/NativeAlertManager.js b/Libraries/Alert/NativeAlertManager.js index 16191e7e4721e9..1dcae0d265bd17 100644 --- a/Libraries/Alert/NativeAlertManager.js +++ b/Libraries/Alert/NativeAlertManager.js @@ -13,27 +13,10 @@ import type {TurboModule} from '../TurboModule/RCTExport'; import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; -export type Buttons = Array<{ - text?: string, - onPress?: ?Function, - style?: AlertButtonStyle, -}>; - -export type Options = { - cancelable?: ?boolean, - onDismiss?: ?() => void, -}; - -/* 'default' | plain-text' | 'secure-text' | 'login-password' */ -export type AlertType = string; - -/* 'default' | 'cancel' | 'destructive' */ -export type AlertButtonStyle = string; - export type Args = {| title?: string, message?: string, - buttons?: Buttons, + buttons?: Object, // TODO: have a better type type?: string, defaultValue?: string, cancelButtonKey?: string, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js index 9eb60e68194b81..ccfcd4928180d1 100644 --- a/Libraries/ReactNative/NativeUIManager.js +++ b/Libraries/ReactNative/NativeUIManager.js @@ -30,7 +30,7 @@ export interface Spec extends TurboModule { +blur: (reactTag: ?number) => void; +findSubviewIn: ( reactTag: ?number, - point: [number, number], + point: Array, callback: ( nativeViewTag: number, left: number, From 1f8e08a4fad28e42c1cf9f886a850c538ff038c4 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Tue, 11 Jun 2019 00:22:11 -0700 Subject: [PATCH 167/330] Move ImageEditor JS files to FB internal Summary: This module is being removed from RN as part of the Lean Core effort. Reviewed By: TheSavior Differential Revision: D15714507 fbshipit-source-id: bb5dc2025a25ad450d6971e5948e7a2e678a9a25 --- Libraries/Image/ImageEditor.js | 71 ------------------- Libraries/Image/NativeImageEditor.js | 25 ------- .../react-native-implementation.js | 22 +++--- 3 files changed, 13 insertions(+), 105 deletions(-) delete mode 100644 Libraries/Image/ImageEditor.js delete mode 100644 Libraries/Image/NativeImageEditor.js diff --git a/Libraries/Image/ImageEditor.js b/Libraries/Image/ImageEditor.js deleted file mode 100644 index 69a7a9121e0783..00000000000000 --- a/Libraries/Image/ImageEditor.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; -import NativeImageEditor from './NativeImageEditor'; - -type ImageCropData = { - /** - * The top-left corner of the cropped image, specified in the original - * image's coordinate space. - */ - offset: {| - x: number, - y: number, - |}, - /** - * The size (dimensions) of the cropped image, specified in the original - * image's coordinate space. - */ - size: {| - width: number, - height: number, - |}, - /** - * (Optional) size to scale the cropped image to. - */ - displaySize?: ?{| - width: number, - height: number, - |}, - /** - * (Optional) the resizing mode to use when scaling the image. If the - * `displaySize` param is not specified, this has no effect. - */ - resizeMode?: ?$Keys<{ - contain: string, - cover: string, - stretch: string, - }>, -}; - -class ImageEditor { - /** - * Crop the image specified by the URI param. If URI points to a remote - * image, it will be downloaded automatically. If the image cannot be - * loaded/downloaded, the failure callback will be called. On Android, a - * downloaded image may be cached in external storage, a publicly accessible - * location, if it has more available space than internal storage. - * - * If the cropping process is successful, the resultant cropped image - * will be stored in the ImageStore, and the URI returned in the success - * callback will point to the image in the store. Remember to delete the - * cropped image from the ImageStore when you are done with it. - */ - static cropImage( - uri: string, - cropData: ImageCropData, - success: (uri: string) => void, - failure: (error: Object) => void, - ) { - NativeImageEditor.cropImage(uri, cropData, success, failure); - } -} - -module.exports = ImageEditor; diff --git a/Libraries/Image/NativeImageEditor.js b/Libraries/Image/NativeImageEditor.js deleted file mode 100644 index e208cb47b6df1c..00000000000000 --- a/Libraries/Image/NativeImageEditor.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -import type {TurboModule} from '../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - +cropImage: ( - uri: string, - options: Object, // TODO: type this better - success: (uri: string) => void, - error: (error: string) => void, - ) => void; -} - -export default TurboModuleRegistry.getEnforcing('ImageEditingManager'); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index bc20dfac8f27c2..d22e4f2ac84a8d 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -52,15 +52,6 @@ module.exports = { get ImageBackground() { return require('../Image/ImageBackground'); }, - get ImageEditor() { - warnOnce( - 'image-editor-moved', - 'Image Editor has been extracted from react-native core and will be removed in a future release. ' + - "It can now be installed and imported from '@react-native-community/image-editor' instead of 'react-native'. " + - 'See https://github.com/react-native-community/react-native-image-editor', - ); - return require('../Image/ImageEditor'); - }, get InputAccessoryView() { return require('../Components/TextInput/InputAccessoryView'); }, @@ -413,4 +404,17 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access ImageEditor. + Object.defineProperty(module.exports, 'ImageEditor', { + configurable: true, + get() { + invariant( + false, + 'ImageEditor has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-image-editor' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-image-editor', + ); + }, + }); } From f8a400a53fd7f336da3809ab87d88be0cd55b1af Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Tue, 11 Jun 2019 00:22:11 -0700 Subject: [PATCH 168/330] Move ViewPagerAndroid JS code to FB Internal Summary: This module is being removed from React Native via Lean Core. This diff moves all the related JS files to FB internal. Note: I removed two references to previously removed modules from some files in this diff. I hope you don't mind. Reviewed By: TheSavior Differential Revision: D15714919 fbshipit-source-id: 88ea406396b31f5c255e06d9c92b67127c81db4a --- .../AndroidViewPagerNativeComponent.js | 112 ------- .../ViewPager/ViewPagerAndroid.android.js | 277 ---------------- .../ViewPager/ViewPagerAndroid.ios.js | 12 - .../react-native-implementation.js | 22 +- .../ViewPagerAndroidExample.android.js | 302 ------------------ RNTester/js/utils/RNTesterList.android.js | 4 - 6 files changed, 13 insertions(+), 716 deletions(-) delete mode 100644 Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js delete mode 100644 Libraries/Components/ViewPager/ViewPagerAndroid.android.js delete mode 100644 Libraries/Components/ViewPager/ViewPagerAndroid.ios.js delete mode 100644 RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js diff --git a/Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js b/Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js deleted file mode 100644 index 82c7e18fb65d4b..00000000000000 --- a/Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - -import type {SyntheticEvent} from '../../Types/CoreEventTypes'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; -import type {Node} from 'react'; -import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; - -type PageScrollState = 'idle' | 'dragging' | 'settling'; - -type PageScrollEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - offset: number, - |}>, ->; - -type PageScrollStateChangedEvent = SyntheticEvent< - $ReadOnly<{| - pageScrollState: PageScrollState, - |}>, ->; - -type PageSelectedEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - |}>, ->; - -type NativeProps = $ReadOnly<{| - /** - * Index of initial page that should be selected. Use `setPage` method to - * update the page, and `onPageSelected` to monitor page changes - */ - initialPage?: ?number, - - /** - * Executed when transitioning between pages (ether because of animation for - * the requested page change or when user is swiping/dragging between pages) - * The `event.nativeEvent` object for this callback will carry following data: - * - position - index of first page from the left that is currently visible - * - offset - value from range [0,1) describing stage between page transitions. - * Value x means that (1 - x) fraction of the page at "position" index is - * visible, and x fraction of the next page is visible. - */ - onPageScroll?: ?(e: PageScrollEvent) => void, - - /** - * Function called when the page scrolling state has changed. - * The page scrolling state can be in 3 states: - * - idle, meaning there is no interaction with the page scroller happening at the time - * - dragging, meaning there is currently an interaction with the page scroller - * - settling, meaning that there was an interaction with the page scroller, and the - * page scroller is now finishing it's closing or opening animation - */ - onPageScrollStateChanged?: ?(e: PageScrollStateChangedEvent) => void, - - /** - * This callback will be called once ViewPager finish navigating to selected page - * (when user swipes between pages). The `event.nativeEvent` object passed to this - * callback will have following fields: - * - position - index of page that has been selected - */ - onPageSelected?: ?(e: PageSelectedEvent) => void, - - /** - * Blank space to show between pages. This is only visible while scrolling, pages are still - * edge-to-edge. - */ - pageMargin?: ?number, - - /** - * Whether enable showing peekFraction or not. If this is true, the preview of - * last and next page will show in current screen. Defaults to false. - */ - - peekEnabled?: ?boolean, - - /** - * Determines whether the keyboard gets dismissed in response to a drag. - * - 'none' (the default), drags do not dismiss the keyboard. - * - 'on-drag', the keyboard is dismissed when a drag begins. - */ - keyboardDismissMode?: ?('none' | 'on-drag'), - - /** - * When false, the content does not scroll. - * The default value is true. - */ - scrollEnabled?: ?boolean, - - children?: Node, - - style?: ?ViewStyleProp, -|}>; - -type ViewPagerNativeType = Class>; - -module.exports = ((requireNativeComponent( - 'AndroidViewPager', -): any): ViewPagerNativeType); diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js deleted file mode 100644 index 0ffb242736f4b6..00000000000000 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js +++ /dev/null @@ -1,277 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -const React = require('react'); -const ReactNative = require('../../Renderer/shims/ReactNative'); -const UIManager = require('../../ReactNative/UIManager'); - -const dismissKeyboard = require('../../Utilities/dismissKeyboard'); - -const NativeAndroidViewPager = require('./AndroidViewPagerNativeComponent'); - -import type {SyntheticEvent} from '../../Types/CoreEventTypes'; -import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; - -const VIEWPAGER_REF = 'viewPager'; - -type PageScrollState = 'idle' | 'dragging' | 'settling'; - -type PageScrollEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - offset: number, - |}>, ->; - -type PageScrollStateChangedEvent = SyntheticEvent< - $ReadOnly<{| - pageScrollState: PageScrollState, - |}>, ->; - -type PageSelectedEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - |}>, ->; - -export type ViewPagerScrollState = $Keys<{ - idle: string, - dragging: string, - settling: string, -}>; - -type Props = $ReadOnly<{| - /** - * Index of initial page that should be selected. Use `setPage` method to - * update the page, and `onPageSelected` to monitor page changes - */ - initialPage?: ?number, - - /** - * Executed when transitioning between pages (ether because of animation for - * the requested page change or when user is swiping/dragging between pages) - * The `event.nativeEvent` object for this callback will carry following data: - * - position - index of first page from the left that is currently visible - * - offset - value from range [0,1) describing stage between page transitions. - * Value x means that (1 - x) fraction of the page at "position" index is - * visible, and x fraction of the next page is visible. - */ - onPageScroll?: ?(e: PageScrollEvent) => void, - - /** - * Function called when the page scrolling state has changed. - * The page scrolling state can be in 3 states: - * - idle, meaning there is no interaction with the page scroller happening at the time - * - dragging, meaning there is currently an interaction with the page scroller - * - settling, meaning that there was an interaction with the page scroller, and the - * page scroller is now finishing it's closing or opening animation - */ - onPageScrollStateChanged?: ?(e: PageScrollStateChangedEvent) => void, - - /** - * This callback will be called once ViewPager finish navigating to selected page - * (when user swipes between pages). The `event.nativeEvent` object passed to this - * callback will have following fields: - * - position - index of page that has been selected - */ - onPageSelected?: ?(e: PageSelectedEvent) => void, - - /** - * Blank space to show between pages. This is only visible while scrolling, pages are still - * edge-to-edge. - */ - pageMargin?: ?number, - - /** - * Whether enable showing peekFraction or not. If this is true, the preview of - * last and next page will show in current screen. Defaults to false. - */ - - peekEnabled?: ?boolean, - - /** - * Determines whether the keyboard gets dismissed in response to a drag. - * - 'none' (the default), drags do not dismiss the keyboard. - * - 'on-drag', the keyboard is dismissed when a drag begins. - */ - keyboardDismissMode?: ?('none' | 'on-drag'), - - /** - * When false, the content does not scroll. - * The default value is true. - */ - scrollEnabled?: ?boolean, - - children?: React.Node, - - style?: ?ViewStyleProp, -|}>; - -/** - * Container that allows to flip left and right between child views. Each - * child view of the `ViewPagerAndroid` will be treated as a separate page - * and will be stretched to fill the `ViewPagerAndroid`. - * - * It is important all children are ``s and not composite components. - * You can set style properties like `padding` or `backgroundColor` for each - * child. It is also important that each child have a `key` prop. - * - * Example: - * - * ``` - * render: function() { - * return ( - * - * - * First page - * - * - * Second page - * - * - * ); - * } - * - * ... - * - * var styles = { - * ... - * viewPager: { - * flex: 1 - * }, - * pageStyle: { - * alignItems: 'center', - * padding: 20, - * } - * } - * ``` - */ - -class ViewPagerAndroid extends React.Component { - componentDidMount() { - if (this.props.initialPage != null) { - this.setPageWithoutAnimation(this.props.initialPage); - } - } - - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - getInnerViewNode = (): ReactComponent => { - return this.refs[VIEWPAGER_REF].getInnerViewNode(); - }; - - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - _childrenWithOverridenStyle = (): Array => { - // Override styles so that each page will fill the parent. Native component - // will handle positioning of elements, so it's not important to offset - // them correctly. - return React.Children.map(this.props.children, function(child) { - if (!child) { - return null; - } - const newProps = { - ...child.props, - style: [ - child.props.style, - { - position: 'absolute', - left: 0, - top: 0, - right: 0, - bottom: 0, - width: undefined, - height: undefined, - }, - ], - collapsable: false, - }; - if ( - child.type && - child.type.displayName && - child.type.displayName !== 'RCTView' && - child.type.displayName !== 'View' - ) { - console.warn( - 'Each ViewPager child must be a . Was ' + - child.type.displayName, - ); - } - return React.createElement(child.type, newProps); - }); - }; - - _onPageScroll = (e: PageScrollEvent) => { - if (this.props.onPageScroll) { - this.props.onPageScroll(e); - } - if (this.props.keyboardDismissMode === 'on-drag') { - dismissKeyboard(); - } - }; - - _onPageScrollStateChanged = (e: PageScrollStateChangedEvent) => { - if (this.props.onPageScrollStateChanged) { - this.props.onPageScrollStateChanged(e); - } - }; - - _onPageSelected = (e: PageSelectedEvent) => { - if (this.props.onPageSelected) { - this.props.onPageSelected(e); - } - }; - - /** - * A helper function to scroll to a specific page in the ViewPager. - * The transition between pages will be animated. - */ - setPage = (selectedPage: number) => { - UIManager.dispatchViewManagerCommand( - ReactNative.findNodeHandle(this), - UIManager.getViewManagerConfig('AndroidViewPager').Commands.setPage, - [selectedPage], - ); - }; - - /** - * A helper function to scroll to a specific page in the ViewPager. - * The transition between pages will *not* be animated. - */ - setPageWithoutAnimation = (selectedPage: number) => { - UIManager.dispatchViewManagerCommand( - ReactNative.findNodeHandle(this), - UIManager.getViewManagerConfig('AndroidViewPager').Commands - .setPageWithoutAnimation, - [selectedPage], - ); - }; - - render() { - return ( - - ); - } -} - -module.exports = ViewPagerAndroid; diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js deleted file mode 100644 index d5fd5cf83f7560..00000000000000 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -module.exports = require('../UnimplementedViews/UnimplementedView'); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index d22e4f2ac84a8d..bea2d5cd5cb491 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -136,15 +136,6 @@ module.exports = { get View() { return require('../Components/View/View'); }, - get ViewPagerAndroid() { - warnOnce( - 'viewpager-moved', - 'ViewPagerAndroid has been extracted from react-native core and will be removed in a future release. ' + - "It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. " + - 'See https://github.com/react-native-community/react-native-viewpager', - ); - return require('../Components/ViewPager/ViewPagerAndroid'); - }, get VirtualizedList() { return require('../Lists/VirtualizedList'); }, @@ -417,4 +408,17 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access ViewPagerAndroid. + Object.defineProperty(module.exports, 'ViewPagerAndroid', { + configurable: true, + get() { + invariant( + false, + 'ViewPagerAndroid has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-viewpager' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-viewpager', + ); + }, + }); } diff --git a/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js b/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js deleted file mode 100644 index 579d6f76495379..00000000000000 --- a/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js +++ /dev/null @@ -1,302 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -const React = require('react'); -const { - Image, - StyleSheet, - Text, - TouchableWithoutFeedback, - TouchableOpacity, - View, - ViewPagerAndroid, -} = require('react-native'); - -import type {ViewPagerScrollState} from '../../../../Libraries/Components/ViewPager/ViewPagerAndroid'; - -const PAGES = 5; -const BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273']; -const IMAGE_URIS = [ - 'https://apod.nasa.gov/apod/image/1410/20141008tleBaldridge001h990.jpg', - 'https://apod.nasa.gov/apod/image/1409/volcanicpillar_vetter_960.jpg', - 'https://apod.nasa.gov/apod/image/1409/m27_snyder_960.jpg', - 'https://apod.nasa.gov/apod/image/1409/PupAmulti_rot0.jpg', - 'https://apod.nasa.gov/apod/image/1510/lunareclipse_27Sep_beletskycrop4.jpg', -]; - -type Props = $ReadOnly<{||}>; -type State = {|likes: number|}; -class LikeCount extends React.Component { - state = { - likes: 7, - }; - - onClick = () => { - this.setState({likes: this.state.likes + 1}); - }; - - render() { - const thumbsUp = '\uD83D\uDC4D'; - return ( - - - {thumbsUp + ' Like'} - - {this.state.likes + ' likes'} - - ); - } -} - -class Button extends React.Component { - _handlePress = () => { - if (this.props.enabled && this.props.onPress) { - this.props.onPress(); - } - }; - - render() { - return ( - - - {this.props.text} - - - ); - } -} - -class ProgressBar extends React.Component { - render() { - const fractionalPosition = - this.props.progress.position + this.props.progress.offset; - const progressBarSize = - (fractionalPosition / (PAGES - 1)) * this.props.size; - return ( - - - - ); - } -} - -class ViewPagerAndroidExample extends React.Component { - state = { - page: 0, - animationsAreEnabled: true, - scrollEnabled: true, - progress: { - position: 0, - offset: 0, - }, - }; - - onPageSelected = e => { - this.setState({page: e.nativeEvent.position}); - }; - - onPageScroll = e => { - this.setState({progress: e.nativeEvent}); - }; - - onPageScrollStateChanged = (state: ViewPagerScrollState) => { - this.setState({scrollState: state}); - }; - - move = delta => { - const page = this.state.page + delta; - this.go(page); - }; - - go = page => { - if (this.state.animationsAreEnabled) { - this.viewPager.setPage(page); - } else { - this.viewPager.setPageWithoutAnimation(page); - } - - this.setState({page}); - }; - - render() { - const pages = []; - for (let i = 0; i < PAGES; i++) { - const pageStyle = { - backgroundColor: BGCOLOR[i % BGCOLOR.length], - alignItems: 'center', - padding: 20, - }; - pages.push( - - - - , - ); - } - const {page, animationsAreEnabled} = this.state; - return ( - - { - this.viewPager = viewPager; - }}> - {pages} - - -